After you've created your payments app and extension, learned about the payments app actions and published your payments app and extension, you must make sure you've implemented the following protocols to be approved as a payments app. ## Requirements - You've created a payments app. - You've made sure your payments app meets [the requirements](/docs/apps/build/payments/requirements). - Your app has the `write_payment_gateways` and `write_payment_sessions` access scopes. > Note: > These are restricted scopes, and you need to [apply](/docs/apps/build/payments/payments-extension-review) for access. ## mTLS configuration Payments apps need to implement [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication#mTLS) to handle all requests where the app acts as the server and Shopify acts as the client, such as when Shopify initiates sessions with payments apps for `payment`, `refund`, `capture`, and `void` requests. In these cases, Shopify uses its own client certificate. Payments apps need to use the provided [self-signed CA](#shopifys-self-signed-certificate-authority-ca) to validate Shopify's certificate. Using mTLS in these scenarios allows payments apps to verify that the client initiating the request is Shopify and that the traffic between Shopify and the payments app is trusted and secure. Because mTLS is mutual, the payments app also needs to provide a certificate that Shopify will validate. For this certificate, you need to use a [Trusted CA Signed SSL Certificate](/docs/apps/build/security/encrypt-with-tls), and not Shopify’s self-signed CA. > Note: > mTLS isn’t used to retrieve the [OAuth access token](/docs/apps/build/authentication-authorization). All requests that use Shopify GraphQL mutations are authenticated with an OAuth access token, not mTLS. ## Shopify's self-signed Certificate Authority (CA) Shopify uses a self-signed CA chain. This means you must add this CA chain to your web server trust store in order for it to be recognized when Shopify makes requests to your payment app server. By adding Shopify's self-signed CA and enforcing mTLS on your web server you are adding a security measure to ensure your web server can distinguish requests originating from Shopify. ### Current CA chain

### Full CA chain If your web server doesn't support receiving the CA chain within the request sent by Shopify, but instead requires the full CA chain to be stored in your web server's trust store (for example, [Amazon `API Gateway`](https://docs.aws.amazon.com/apigateway/latest/developerguide/rest-api-mutual-tls.html)), then you require both the Intermediate and Root CA:

We will continue to send the leaf certificate in any request we make to the web server URL you set in your payment extension config. ## Idempotency Payments Apps APIs support idempotency, which allows Shopify to safely retry requests without accidentally performing the same operation twice. Idempotency is critical in cases where there are network errors to prevent, such as multiple charges for the same payment. Idempotency keys don't expire. ### HTTP requests from Shopify to your payments app You need to support idempotent requests for the Payments Apps APIs. Regardless of how many requests with the same idempotency key are sent, the result must be the same. The idempotency key attributes are defined on a per-API basis in the [payment request body](/docs/apps/build/payments/request-reference). ### GraphQL requests from your payments app to Shopify Idempotency is implemented on a per mutation basis for a given `id`. If multiple requests of the same mutation are made, then the mutation will only be performed once during the first request, and the same response will be returned in subsequent requests. For instance, if several requests for [`paymentSessionResolve`](/docs/api/payments-apps/latest/mutations/paymentSessionResolve) are made using the same `id`, then the mutation will only be executed once. Some mutations are mutually exclusive, such as [`paymentSessionResolve`](/docs/api/payments-apps/latest/mutations/paymentSessionResolve) and [`paymentSessionReject`](/docs/api/payments-apps/latest/mutations/paymentSessionReject), where only one can be processed for a given `id`. If requests for different mutations are submitted using the same `id`, then the first request to be received will be processed, and any subsequent requests with incompatible mutation will fail with a [`user_error`](/docs/api/payments-apps/latest/objects/UserError). ## Retry policy Due to the asynchronous nature of Shopify's Payments Apps APIs, you must send a GraphQL request to notify Shopify of the results of any payment or refund requests. A retry policy helps provide data consistency between merchants, Partners, and Shopify. You must implement a retry policy for the [Payments Apps API mutations](/docs/api/payments-apps). If there's a Shopify service disruption (or if 5xx status codes are being returned), then requests must be retried according to the following incremental strategy, up to a total of 18 retries over 24h. During this time, you can provide the customer with the following information: - Their payment is processed, but Shopify is unreachable. - They'll receive a notification from Shopify when the order is processed. - They should contact the merchant directly if the maximum number of recommended retries elapses without acknowledgment. | Parameter | Description | Value | |-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| | **Number of recommended retries** | The maximum number of recommended retries. | 18 | | **Base delay interval** | The time interval after which the first retry is attempted. | 5 seconds | | **Exponential backoff factor** | Partners are expected to retry their requests immediately, and then 5 seconds afterwards, and then at increasing time intervals after that, until the request is acknowledged or 24 hours has passed, whichever comes first. | See example | **Example:** [0 seconds, 5 seconds, 10 seconds, 30 seconds, 45 seconds, 1 minute, 2 minutes, 5 minutes, 12 minutes, 38 minutes, 1 hour, 2 hours] + [4 hours] * 5 ## Rate limiting To protect the stability of the platform, payments apps are rate-limited. For more information, refer to [Shopify API rate limits](/docs/api/usage/rate-limits#compare-rate-limits-by-api). ## Next steps Learn how to [onboard a merchant to your payment app](/docs/apps/build/payments/onboard-a-merchant-payments-extension).