Processing a payment
Payment processing begins when Shopify makes an HTTP call to your payments app. Your app responds with a redirect URL that Shopify uses to redirect the customer to your app's payment page. After the payment is finalized, you need to communicate the result to Shopify using either PaymentSessionResolve or PaymentSessionReject.
How the payments app flow works
The following diagram illustrates how a payment flow works between the payments app and Shopify:
- The customer completes checkout, triggering a request for payment.
- Shopify sends a backend request to the payments app, specifying the amount and currency to be charged.
- The app responds with a redirect URL for a payment page hosted by the partner's app. (200 OK)
- Shopify redirects the customer to the redirect URL.
- The payments app collects the buyer’s payment credentials and processes the payment as described in the backend request.
- The payments app communicates the payment processing result to Shopify, implementing a retry policy as needed.
- Shopify replies with the redirect URL. (200 OK)
- The app redirects the customer to Shopify. (301 Redirect)
- Customer continues checkout.
For payment processing, both upstream and downstream requests must be idempotent with the
payment ID used as the idempotency key.
Payment processing relies on asynchronous communications over HTTP between Shopify and the payments app. In an asynchronous system, retry policies are crucial to ensure a robust communication strategy.
- You've completed the Getting started building payments apps guide.
- You've familiarized yourself with the general transaction requirements.
- To be eligible to build payments apps, you must meet the payments apps requirements.
To use the GraphQL mutations, your app needs to be aware of access scopes for payments apps.
Initiate the payment flow
The payment flow begins with an HTTP request sent from Shopify to the provider's payment session URL provided during app extension configuration. This request contains information about the customer and the order.
||Unique identifier for the payment attempt. Used as the idempotency key. It can be assumed that requests with a given ID are identical to any previously received requests with the same ID. This ID must be surfaced to the merchant so that they can correlate Shopify orders with payments managed by the partner app.||
||Identifies the payment when communicating with Shopify (in GraphQL mutations, for example).||
||A customer might open multiple tabs in their browser for a given order. All of those tabs will be associated with the same group. As a result, Shopify can initiate multiple payment flows for the same
||The amount to be charged. The value is always sent using a decimal point as a separator, regardless of locale.||
||The URL to redirect the customer to when the customer quits the payment flow and returns to the merchant's website. The `cancel_url` attribute should only be used when a customer is on the provider page and decides to cancel their payment and return to Shopify.||
||Can be used to order payment attempts that are a part of the same group.||
||Indicates whether the payment is in test or live mode. Refer to Test mode for more information.||
||If customer is included, then one of
||The permanent domain of the merchant. Can be used to identify which merchant is initiating the payment.|
||Unique per request. Can be used to track specific requests for troubleshooting.|
||The API version selected in the payments app configuration. The version selected defines the response payload's format expected by the payments app.|
Shopify must receive a HTTP 2xx response for the payment session creation to be successful. If the request fails, then it will be retried a number of times and will eventually transition to an "aborted" state, at which point the buyer will have to retry their payment through Shopify checkout. The response must contain the URL for the partner page where Shopify will redirect the buyer.
If there's an error on the payment apps side, don't respond with a 2xx. Use an appropriate error status code instead.
Resolve a Payment
You must invoke the PaymentSessionResolve mutation after the buyer has successfully gone through the process of paying:
id argument corresponds to the
gid of the payment.
redirectUrl field is the URL to which the buyer is to be redirected by the partner.
Reject a Payment
A payment should be rejected when the buyer is unable to complete payment with the provider. This signals to Shopify that the checkout process is to be halted.
You can reject a payment using the PaymentSessionReject mutation:
The rejection requires information on why the payment was rejected. This information is encapsulated in the PaymentSessionRejectionReasonInput.
PaymentSessionRejectionReasonInput.code is a
PaymentSessionStatusReasonRejectionCode, which is an enum of of standardized error codes.
PaymentSessionRejectionReasonInput.merchantMessage argument is a localized error message presented to the merchant explaining why the payment was rejected.
If there's a Shopify service disruption (or if 5xx status codes are being returned), then requests must be retried. It's suggested to follow the guidelines in the retry policy section.
If a GraphQL request acknowledgment is not received, then you need to implement a retry policy. During this time, you can inform the customer that the payment is processed, but Shopify is unreachable. You can let the customer know that they will receive a notification from Shopify when the order is processed. Furthermore, the customer should contact the merchant directly if the maximum number of recommended retries elapses without acknowledgment.
The nextAction will either be nil or contain two fields. In the case where it is nil, no next action is expected of the payments app.
Otherwise, the fields are as follows:
action: An enum that specifies the type of the action the app must perform.
context: Union type requiring inline fragments to access data on the underlying type. Takes a type of PaymentSessionActionsRedirect