Stripe APM Offsite Payments

Spreedly supports purchases with alternative payment methods (APMs) by leveraging Stripe’s Payment Element framework. The process for creating a charge on an alternate payment method is described in detail below. At a high level, the general steps are as follows:

  1. Create a pending transaction on a Stripe Payment Intents gateway that contains information about how much will be charged, what alternative payment methods will be accepted, and where the customer should be redirected when the transaction is complete.
  2. Include Spreedly’s iFrame library on your frontend and use it to display the Stripe Payment Element using data from the pending transaction.
  3. Use Spreedly’s iFrame library on your frontend to redirect the user to complete the payment.
  4. Receive the customer back at the URL given in Step 1. Query Spreedly for the transaction state and handle the flow for the customer accordingly.
  5. Receive callbacks from Spreedly with updates on APM transactions. Some payments method types can take a long time to fully resolve; callbacks are how Spreedly can alert merchants of payment updates outside of the checkout flow.

Stripe APM Flow Diagram

To perform a payment with APMs, the merchant account at Stripe needs to be set up to accept a given payment method type. Please refer to the Stripe dashboard for more information on what payment methods are accepted for your account.

Step 1: Create a pending purchase

The first step in making a transaction using alternate payment methods is to create a pending transaction that contains information about how much will be charged, what alternative payment methods will be accepted, and where the customer should be redirected when they have completed the payment. The stripe_apm payment method type is only supported on the Stripe Payment Intents gateway.

curl https://core.spreedly.com/v1/gateways/LlkjmEk0xNkcWrNixXa1fvNoTP4/purchase.json \
 -u 'C7cRfNJGODKh4Iu5Ox3PToKjniY:4UIuWybmdythfNGPqAqyQnYha6s451ri0fYAo4p3drZUi7q2Jf4b7HKg8etDtoKJ' \
 -H 'Content-Type: application/xml' \
 -d '{
    "transaction": {
      "amount": 1000,
      "currency_code": "EUR",
      "redirect_url": "https://merchant-site.com/handle-redirect",
      "callback_url": "https://merchant-site.com/handle-callbacks",
      "payment_method": {
        "payment_method_type": "stripe_apm",
        "apm_types": ["ideal", "bancontact"]
      }
    }
  }'

If the transaction state is pending in the response, proceed to Step 2 to present the Payment Element to your customer. If the transaction state is failed, gateway_processing_failed, or gateway_processing_unknown, the transaction should be corrected with the information returned by the error and tried again.

For a full list of supported values accepted by the apm_types field, refer to Stripe’s documentation on payment method types supported by the Payment Element. Please note that Spreedly does not support the card payment method type.

Step 2: Display the Stripe Payment Element

Once the transaction has been created, a Stripe Payment Element form can be shown using Spreedly’s iFrame:

const element = Spreedly.createStripePaymentElement({
  publishableKey: 'pk_...',
  clientSecret: clientSecret,
  paymentElement: '#payment-element',
  transactionToken: spreedlyTransactionToken,
  appearance: stripeAppearanceObject
});
  • publishableKey: The publishable key attached to the Stripe account making this purchase. This value can be found in the Stripe developer dashboard.
  • clientSecret: The client secret is a field returned in the pending transaction from Step 1 that authorizes the frontend to complete the purchase. This value can be found in the Spreedly transaction response at transaction.gateway_specific_response_fields.stripe_payment_intents.client_secret.
  • spreedlyTransactionToken: The Spreedly transaction token returned by the pending transaction from Step 1.
  • paymentElement: An HTML DOM element that the Payment Element will be injected into.
  • appearance (optional): For more information on the appearance object, see Stripe’s Appearance API documentation.

The response of this call is an object that must be saved to a variable for use in Step 3. For more details on this function, see our iFrame Reference.

Step 3: Redirect the customer to complete their purchase

Once the customer has finished filling in the Stripe Payment Element form, you will need to redirect them to complete their payment. The following function should be called upon the customer clicking the checkout button, where element is the object returned in Step 2:

// On Checkout:
element.confirmPayment();

This function call will make an API request to Stripe and then redirect the customer off of the current page to finish their payment. After it is called, it is recommended that the checkout button be disabled until the redirect occurs.

Step 4: Receive the customer back

The customer will now complete their off-site authorization of the payment. Once finished, they will be redirected to Spreedly, where we will update our transaction status, and then to the redirect_url given in the pending purchase created in Step 1. When the customer is redirected back to the merchant site, the merchant should query Spreedly to receive the updated state of the transaction using our Transaction Show endpoint. There are six transaction status values that should be accounted for:

  • succeeded: the transaction was completed successfully and funds were received.
  • processing: the transaction was accepted, funds were not yet received. This state is used for some payment methods like SEPA debit where the transaction can be accepted but its final state is not known when the redirect completes. For example, SEPA debit transactions may take up to 14 days to receive a completion. The final success or failure for these transactions will not happen as part of the purchase flow, but via callbacks that happen much later. See Step 5 below for more information on processing Spreedly callbacks.
  • pending: for many payment failures, the transaction will remain in the pending state for the merchant to prompt the customer to try another payment method. The Payment Element can be displayed again using the same information as Step 2.
  • failed, gateway_processing_failed, gateway_processing_result_unknown: an error has occurred or the payment is no longer processable. A new transaction will need to be created in order to attempt this payment again. See our debugging guide for more information on troubleshooting failures.

Step 5: Handle Callbacks

Whenever Spreedly updates the state of a pending transaction due to a redirect or receipt of a Stripe webhook, we in turn send a callback to the callback_url given in the initial transaction in Part 1. Processing these callbacks is required for payment methods like SEPA debit where the completion happens long after the payment flow, and useful for other payment methods in case there is a failure during redirecting a customer back to the merchant site.

For Spreedly to receive updates, integrators must create a Stripe webhook that sends payment callbacks to the Spreedly server. This webhook can be set up in the same way as webhooks that are set up for Spreedly’s 3DS integration except that it requires a different set of events that it listens for. For an APM integration, the webhook that is set up must listen for all Payment Intent events. For instructions on setting up a Stripe webhook, please see the 3DS transactions section of our Stripe Payment Intents gateway guide.

For more information on callbacks, see Spreedly’s Offsite Payments documentation.