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 the
PaymentSessionReject mutations. After the
PaymentSessionReject mutation is called, you can't change the payment state.
This guide assumes that you have:
- Created a payments app
- Made sure your app meets the payments apps requirements
- Applied for access to the required access scopes for payments apps
How the payments app flow worksAnchor link to section titled "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. (
- Shopify redirects the customer to the redirect URL.
- The payments app collects the customer’s payment credentials and processes the payment as described in the backend request.
- The payments app sends the result of the payment to Shopify, which is either (resolve, reject, or pend), implementing a retry policy as needed.
- Shopify responds with the redirect URL, and sends a
200(OK) HTTP status.
- The payments app redirects the customer to Shopify, and sends a
301(Moved permanently) HTTP status.
- The customer continues to checkout.
For payment processing, both upstream and downstream requests must be idempotent with the
payment ID used as the idempotency key.
How a payment flow worksAnchor link to section titled "How a payment flow works"
The payment flow begins with an HTTP POST request sent from Shopify to the provider's payment session URL provided during the payments app extension configuration. This request contains information about the customer and the order.
Request body exampleAnchor link to section titled "Request body example"
||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.||
||Three-letter ISO 4217 currency code.||
||Indicates whether the payment is in test or live mode. Refer to Test mode for more information.||
||IETF BCP 47 language tag representing the language used by the merchant.||
||Hash giving details on the payment method used. It contains two subfields:
||The URL to redirect the customer 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.||
If customer is included, then at least one of
Request headers exampleAnchor link to section titled "Request headers example"
||The permanent domain of the merchant's shop. Can be used to identify which shop is initiating the payment.|
||The unique request ID used to track specific requests for troubleshooting purposes.|
||The API version selected in the payments app configuration. The version selected defines the response payload's format expected by the payments app.|
HTTP response exampleAnchor link to section titled "HTTP response example"
Shopify must receive an 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. If the aborted state is reached, then the customer has to retry their payment through Shopify checkout. The response must contain the URL for the Partner page where Shopify redirects the customer.
If there's an error on the payment apps side, then don't respond with an HTTP
2xx. Use an appropriate error status code instead.
Resolve a paymentAnchor link to section titled "Resolve a payment"
You must use the paymentSessionResolve mutation after the customer has successfully gone through the payment process. The
id argument corresponds to the global identifer (
gid) of the payment:
redirectUrl field is the URL to which the customer is to be redirected by the Partner.
Reject a paymentAnchor link to section titled "Reject a payment"
The payments app should reject a payment if the customer can't complete a payment with the provider. The rejected payment tells Shopify that the checkout process will be halted. For example, if you don't want to process a high-risk payment, then you can reject the payment using the
Rejecting a payment is final. You can't call other actions on a payment after it has been rejected. The payments app should retry a failed user attempt and complete the payment before calling the PaymentSessionReject. For example, if any of the following conditions are met, then you don't need to reject the payment:
- The user doesn't interact with your payments app
- The user cancels the payment
- The user needs to retry the payment because of specific errors, such as user entering the wrong CVV
You can reject a payment using the paymentSessionReject mutation, as seen in the example below:
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.
Pend a paymentAnchor link to section titled "Pend a payment"
You can pend a payment if it's awaiting asynchronous action by the customer, the payment Partner, or a payment network.
Not all payments can be processed and finalized quickly. Some payments can take several days to complete. Pending a payment indicates to the customer that you have started processing the payment, but require more time to complete the payment.
Upon completion, pending payments must be finalized into either a successful or failed state using the
paymentSessionReject mutations. Both
authorization payments can be marked as pending.
To pend a payment, use the
idcorresponds to the global identifier (
gid) of the payment
pendingExpiresAtcorresponds to the date and time when the pending payment expires and must be within three days of calling the
reasoncorresponds to the reason why the payment is pending. Can be one of
Cancel a paymentAnchor link to section titled "Cancel a payment"
If a customer wants to cancel a payment on your provider page, then you can redirect the customer to the merchant's website or store by using the
cancel_url is sent to your payments app in the payment request that was sent from Shopify. You should not use the
PaymentSessionReject mutation to cancel the payment, otherwise the customer will be unable to pay again with your provider. For more information on when to use the
PaymentSessionReject mutation, refer to Reject a payment.
Retry policyAnchor link to section titled "Retry policy"
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.
Next actionAnchor link to section titled "Next action"
Upon receiving the response from either the PaymentSessionResolve, PaymentSessionReject, or paymentSessionPending mutations, the next action that the payments app needs to perform is specified under
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: