MPP.Methods.Stripe (mpp v0.14.0)

Copy Markdown View Source

Stripe payment method for one-time charges and recurring subscriptions.

The client creates a Shared Payment Granted Token (SPT) via Stripe, includes it in the credential payload, and the server creates a PaymentIntent with confirm: true to charge it immediately.

Configuration

Pass Stripe-specific config via :method_config in MPP.Plug opts:

plug MPP.Plug,
  secret_key: "hmac-secret",
  realm: "api.example.com",
  method: MPP.Methods.Stripe,
  amount: "5000",
  currency: "usd",
  method_config: %{
    "stripe_secret_key" => "sk_test_...",
    "network_id" => "profile_1Mqx...",
    "payment_method_types" => ["card"]
  }

Config Keys

  • "stripe_secret_key" — (required) Stripe secret key for PaymentIntent creation
  • "network_id" — (required) Stripe Business Network profile ID
  • "payment_method_types" — (optional) accepted payment methods, defaults to ["card"]
  • "connect" — (optional) server-side Stripe Connect settlement policy (see below)
  • "realm" — (optional, injected by Plug) server realm for analytics metadata

Stripe Connect settlement

Pass a "connect" map in method_config to route the resulting PaymentIntent to a connected account (destination charge, direct charge, or application-fee split). Connect settlement is a server-only credential — it is merged into the charge at verify time and is never serialized into the public 402 challenge, matching the mppx reference (src/stripe/server/Charge.ts, where connect is documented as "Not included in MPP challenges").

method_config: %{
  "stripe_secret_key" => "sk_test_...",
  "network_id" => "profile_1Mqx...",
  "connect" => %{
    # Destination charge: platform is merchant of record, funds routed on.
    "transfer_data" => %{"destination" => "acct_seller", "amount" => 4000},
    "application_fee_amount" => 500,
    "on_behalf_of" => "acct_seller",
    "transfer_group" => "order_42",
    # Direct charge: run the PaymentIntent on the connected account itself.
    "stripe_account" => "acct_seller"
  }
}

Wire mapping applied to the PaymentIntent (form-encoded), per the mppx reference:

  • "application_fee_amount" (integer) → application_fee_amount
  • "on_behalf_of" (string) → on_behalf_of
  • "transfer_data" %{"destination" => ..., "amount" => ...}transfer_data[destination] / transfer_data[amount]
  • "transfer_group" (string) → transfer_group
  • "stripe_account" (string) → Stripe-Account request header

Settlement is validated against the charge amount before the PaymentIntent is created: account ids must be non-empty, fee/transfer amounts must be non-negative integers not exceeding the payment amount.

Credential Payload

Charge credentials contain:

  • "spt" — (required) Stripe Shared Payment Granted Token (e.g., "spt_1N4...")
  • "externalId" — (optional) caller-provided correlation ID, echoed in receipt

Subscription credentials contain a required "paymentMethod" and an optional existing "customer". Subscription activation follows the constrained Stripe Billing profile in draft-stripe-subscription-00.

API Functions

FunctionArityDescriptionParam Kinds
challenge_method_details1Return Stripe-specific fields (networkId, paymentMethodTypes) for the 402 challenge.charge: value
verify2Verify a Stripe SPT credential by creating a PaymentIntent with confirm: true.payload: value, charge: value
validate_config!1Validate Stripe method_config at init time. Raises on missing stripe_secret_key or network_id.config: value
credential_types0Return the Stripe charge payload types. Stripe uses SPT tokens, not typed hash payloads.-
method_name0Return the payment method identifier for Stripe.-

Summary

Functions

Return Stripe-specific fields (networkId, paymentMethodTypes) for the 402 challenge.

Return the Stripe charge payload types. Stripe uses SPT tokens, not typed hash payloads.

Return the payment method identifier for Stripe.

Validate Stripe method_config at init time. Raises on missing stripe_secret_key or network_id.

Verify a Stripe SPT credential by creating a PaymentIntent with confirm: true.

Functions

challenge_method_details(subscription)

@spec challenge_method_details(MPP.Method.intent()) :: map() | nil
@spec challenge_method_details(MPP.Intents.Charge.t() | MPP.Intents.Subscription.t()) ::
  map() | nil

Return Stripe-specific fields (networkId, paymentMethodTypes) for the 402 challenge.

Parameters

  • charge - Charge struct with method_details containing network_id and optionally payment_method_types (value)

Returns

Map with networkId and paymentMethodTypes keys, or nil if no network_id configured (map_or_nil)

# descripex:contract
%{
  params: %{
    charge: %{
      description: "Charge struct with method_details containing `network_id` and optionally `payment_method_types`",
      kind: :value
    }
  },
  returns: %{
    type: :map_or_nil,
    description: "Map with `networkId` and `paymentMethodTypes` keys, or `nil` if no `network_id` configured"
  }
}

credential_types()

@spec credential_types() :: [String.t()]
@spec credential_types() :: [String.t()]

Return the Stripe charge payload types. Stripe uses SPT tokens, not typed hash payloads.

# descripex:contract
%{}

method_name()

@spec method_name() :: String.t()

Return the payment method identifier for Stripe.

# descripex:contract
%{}

validate_config!(config)

@spec validate_config!(map()) :: :ok
@spec validate_config!(map()) :: :ok

Validate Stripe method_config at init time. Raises on missing stripe_secret_key or network_id.

Parameters

  • config - method_config map to validate (value)

Returns

:ok on success, raises ArgumentError on missing keys (atom)

# descripex:contract
%{
  params: %{
    config: %{description: "method_config map to validate", kind: :value}
  },
  returns: %{
    type: :atom,
    description: "`:ok` on success, raises `ArgumentError` on missing keys"
  }
}

verify(payload, subscription)

@spec verify(map(), MPP.Intents.Charge.t() | MPP.Intents.Subscription.t()) ::
  {:ok, MPP.Receipt.t()} | {:error, MPP.Errors.t()}

Verify a Stripe SPT credential by creating a PaymentIntent with confirm: true.

Parameters

  • payload - Credential payload map containing "spt" (Stripe Shared Payment Granted Token) (value)
  • charge - Charge intent struct with amount, currency, and method_details (including stripe_secret_key) (value)

Returns

{:ok, receipt} on success, {:error, error} on failure (tagged_tuple)

Errors

  • :invalid_payload
  • :verification_failed
# descripex:contract
%{
  params: %{
    payload: %{
      description: "Credential payload map containing `\"spt\"` (Stripe Shared Payment Granted Token)",
      kind: :value
    },
    charge: %{
      description: "Charge intent struct with amount, currency, and method_details (including `stripe_secret_key`)",
      kind: :value
    }
  },
  errors: [:invalid_payload, :verification_failed],
  returns: %{
    type: :tagged_tuple,
    description: "`{:ok, receipt}` on success, `{:error, error}` on failure"
  }
}