# Cash App Pay payments Add support for Cash App Pay to your integration. # Direct API We recommend that you implement the [Elements](https://docs.stripe.com/payments/cash-app-pay/accept-a-payment.md?payment-ui=elements) integration. An Elements integration allows you to add Cash App Pay and other payment methods with significantly less effort than a Direct API integration. Accepting Cash App Pay using a Direct API integration consists of: - Creating a [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) object to track a payment. - Submitting the payment to Stripe for processing. - Authenticating the payment (through a mobile application redirect or QR code). - Handling post-payment events to redirect the customer after an order succeeds or fails. ## Set up Stripe [Server-side] First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). Use our official libraries for access to the Stripe API from your application: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ## Create a PaymentIntent [Server-side] A [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) is an object that represents your intent to collect payment from a customer and tracks the lifecycle of the payment process through each stage. To create a `PaymentIntent` on your server: - Specify the amount to collect and the currency. - [Enable the payment method](https://dashboard.stripe.com/settings/payment_methods) in your Dashboard. Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency and payment flow. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=6000 \ -d currency=usd \ -d "automatic_payment_methods[enabled]=true" ``` ### Retrieve the client secret The PaymentIntent includes a *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)) that the client side uses to securely complete the payment process. You can use different approaches to pass the client secret to the client side. #### Single-page application Retrieve the client secret from an endpoint on your server, using the browser’s `fetch` function. This approach is best if your client side is a single-page application, particularly one built with a modern front-end framework such as React. Create the server endpoint that serves the client secret: #### Ruby ```ruby get '/secret' do intent = # ... Create or retrieve the PaymentIntent {client_secret: intent.client_secret}.to_json end ``` And then fetch the client secret with JavaScript on the client side: ```javascript (async () => { const response = await fetch('/secret'); const {client_secret: clientSecret} = await response.json(); // Render the form using the clientSecret })(); ``` #### Server-side rendering Pass the client secret to the client from your server. This approach works best if your application generates static content on the server before sending it to the browser. Add the [client_secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) in your checkout form. In your server-side code, retrieve the client secret from the PaymentIntent: #### Ruby ```erb
``` ```ruby get '/checkout' do @intent = # ... Fetch or create the PaymentIntent erb :checkout end ``` ## Submit the payment to Stripe and authenticate transactions client-side In this step, you’ll complete Cash App Pay payments on the client with [Stripe.js](https://docs.stripe.com/payments/elements.md). To authenticate a transaction, you must redirect the customer to Cash App. Include the Stripe.js script on your checkout page by adding it to the `head` of your HTML file. ```html Checkout ``` Create an instance of Stripe.js with the following JavaScript on your checkout page: ```javascript // Set your publishable key. Remember to change this to your live publishable key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe('<>'); ``` Use `stripe.confirmCashappPayment` to confirm the PaymentIntent on the client side. ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', function(event) { event.preventDefault(); // Pass the clientSecret obtained from the server in step 2 as the first argument stripe.confirmCashappPayment( clientSecret, { payment_method: { type: 'cashapp', }, return_url: 'https://www.example.com/checkout/done', }, ); }); ``` > `confirmCashappPayment` only redirects mobile browsers to your `return_url`, it doesn’t redirect desktop browsers. You can manually redirect customers using desktop browsers to your return URL after the returned promise resolves. Customers can authenticate Cash App Pay transactions with mobile or desktop apps. The client the customer is using determines the authentication method after calling `confirmCashappPayment`. #### Mobile application authentication After calling `confirmCashappPayment`, the customers are redirected to Cash App to approve or decline the payment. After the customers authorise the payment, they’re redirected to the Payment Intent’s `return_url`. Stripe adds `payment_intent`, `payment_intent_client_secret`, `redirect_pm_type`, and `redirect_status` as URL query parameters (along with any existing query parameters in the `return_url`). An authentication session expires after 60 minutes, and the PaymentIntent’s status transitions back to `require_payment_method`. After the status transitions, the customer sees a payment error and must restart the payment process. #### Desktop web app authentication After calling `confirmCashappPayment`, a QR code displays on the webpage. Your customers can scan the QR code using either their mobile device’s camera or the Cash App mobile application and authenticate the payment. A few seconds after customers authenticate the payment successfully, the QR code modal closes automatically and you can fulfil the order. An authentication session expires after 60 minutes. You can refresh the QR code up to 20 times before the PaymentIntent’s status transitions back to `require_payment_method`. After the status transitions, the customer sees a payment error and must restart the payment process. ## Optional: Handle redirect and authentication manually We recommend using Stripe.js to handle redirects and authentication with `confirmCashappPayment`. However, you can also handle redirects and authentication manually on your server. Specify `handleActions: false` in the `confirmCashappPayment` call. ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', function(event) { event.preventDefault(); // Set the clientSecret here you got in Step 2 stripe.confirmCashappPayment( clientSecret, { payment_method_data: { type: 'cashapp', }, return_url: 'https://www.example.com/checkout/done', }, { handleActions: false }, ).then((result) => { if (result.error) { // Display error to your customer. } else if (result.paymentIntent.status === "requires_action") { const nextAction = result.paymentIntent.next_action.cashapp_handle_redirect_or_display_qr_code; const expiresAt = nextAction.qr_code.expires_at; if (IS_MOBILE) { // This URL redirects the customer to Cash App to approve or decline the payment. const mobileAuthUrl = nextAction.mobile_auth_url; } else if (IS_DESKTOP) { // Render the QR code and display it to the customer using the below image source. const imageUrlSvg = nextAction.qr_code.image_url_svg; const imageUrlPng = nextAction.qr_code.image_url_png; } } }); }); ``` #### Mobile application authentication If a customer is paying with Cash App Pay on a mobile device: 1. Redirect the customer to the URL set as the `result.paymentIntent.next_action.cashapp_handle_redirect_or_display_qr_code.mobile_auth_url` property. This redirects the customer to Cash App to approve or decline the payment. 2. After the customer authorises the payment, they’re redirected to the Payment Intent’s `return_url`. Stripe adds `payment_intent`, `payment_intent_client_secret`, `redirect_pm_type`, and `redirect_status` as URL query parameters (along with any existing query parameters in the `return_url`). 3. The `mobile_auth_url` expires after 30 seconds. In case the customer isn’t redirected to `mobile_auth_url` before expiry, call [stripe.retrievePaymentIntent](https://docs.stripe.com/js/payment_intents/retrieve_payment_intent) to get a new `mobile_auth_url`. #### Desktop web app authentication If a customer is paying with Cash App Pay from a desktop web app: 1. Render the QR code and display it to the customer. Use `result.paymentIntent.next_action.cashapp_handle_redirect_or_display_qr_code.qr_code.image_url_png` or `image_url_svg` as an image source. For example: ```html ``` 2. The customer can scan the QR code using either their mobile device’s camera or the Cash App mobile application. They can then authenticate the payment. 3. Make the customer wait on the QR code page until Stripe fulfils the order and you know the outcome of the payment. Stripe sends the outcome in a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) or a [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.payment_failed) webhook. You can either consume these payment intent webhooks server-side and return the results to the client (for example, with a persistent connection using web-socket) or implement client-side polling on your webpage to periodically fetch the status of the [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md). 4. The QR code expires after 30 seconds. Upon expiry, call [stripe.retrievePaymentIntent](https://docs.stripe.com/js/payment_intents/retrieve_payment_intent) to get a new QR code from `result.paymentIntent.next_action.cashapp_handle_redirect_or_display_qr_code.qr_code`. An authentication session expires after 60 minutes. You can refresh the QR code up to 20 times before the PaymentIntent’s status transitions back to `require_payment_method`. After the status transitions, the customer sees a payment error and must restart the payment process. ## Optional: Separate authorisation and capture You can separate authorisation and capture to create a charge now, but capture funds later. Stripe cancels the PaymentIntent and sends a [payment_intent.canceled](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.canceled) event if the payment isn’t captured during the 7-day window. If you know that you can’t capture the payment, we recommend [cancelling the PaymentIntent](https://docs.stripe.com/refunds.md#cancel-payment) instead of waiting for the 7-day window to elapse. ### Tell Stripe to authorize only To indicate that you want separate authorisation and capture, set [capture_method](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-capture_method) to `manual` when creating the PaymentIntent. This parameter instructs Stripe to only authorise the amount on the customer’s Cash App Pay account. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=6000 \ -d confirm=true \ -d currency=usd \ -d "automatic_payment_methods[enabled]=true" \ -d "payment_method_data[type]=cashapp" \ -d capture_method=manual \ --data-urlencode "return_url=https://www.example.com/checkout/done" ``` ### Capture the funds After the authorisation succeeds, the PaymentIntent [status](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-status) transitions to `requires_capture`. To capture the authorised funds, make a PaymentIntent [capture](https://docs.stripe.com/api/payment_intents/capture.md) request. ```curl curl -X POST https://api.stripe.com/v1/payment_intents/{PAYMENT_INTENT_ID}/capture \ -u "<>:" ``` The total authorized amount is captured by default. You can also specify `amount_to_capture` which can be less or equal to the total. ### (Optional) Cancel the authorisation If you need to cancel an authorisation, you can [cancel the PaymentIntent](https://docs.stripe.com/api/payment_intents/cancel.md). ## Optional: Handle post-payment events Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the Dashboard, a custom *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests), or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events also helps you accept more payment methods in the future. Learn about the [differences between all supported payment methods](https://stripe.com/payments/payment-methods-guide). - **Handle events manually in the Dashboard** Use the Dashboard to [view your payments](https://dashboard.stripe.com/payments), send email receipts, handle payouts, or retry failed payments. - **Build a custom webhook** [Build a custom webhook](https://docs.stripe.com/webhooks/handling-payment-events.md#build-your-own-webhook) handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI. - **Integrate a prebuilt app** Handle common business events, such as [automation](https://stripe.partners/?f_category=automation) or [marketing and sales](https://stripe.partners/?f_category=marketing-and-sales), by integrating a partner application. ## Test your integration #### Mobile web app testing To test your integration, choose Cash App Pay as the payment method and tap **Pay**. While testing, this redirects you to a test payment page where you can approve or decline the payment. In live mode, tapping **Pay** redirects you to the Cash App mobile application – you don’t have the option to approve or decline the payment within Cash App. The payment is automatically approved after the redirect. #### Desktop web app testing To test your integration, scan the QR code with a QR code scanning application on your mobile device. While testing, the QR code payload contains a URL that redirects you to a test payment page where you can approve or decline the test payment. In live mode, scanning the QR code redirects you to the Cash App mobile application – you don’t have the option to approve or decline the payment within Cash App. The payment is automatically approved after you scan the QR code. ## Failed payments Cash App Pay uses multiple data points to decide when to decline a transaction (for example, their AI model detected high consumer fraud risk for the transaction, or the consumer has revoked your permission to charge them in Cash App). In these cases, the [PaymentMethod](https://docs.stripe.com/api/payment_methods/object.md) is detached and the [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) object’s status automatically transitions to `requires_payment_method`. Other than a payment being declined, for a Cash App Pay [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) with a status of `requires_action`, customers must complete the payment within 10 minutes after they’re redirected to Cash App. If no action is taken after 10 minutes, the [PaymentMethod](https://docs.stripe.com/api/payment_methods/object.md) is detached and the [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) object’s status automatically transitions to `requires_payment_method`. When this happens, the Payment Element renders error messages and instructs your customer to retry using a different payment method. ## Error codes The following table details common error codes and recommended actions: | Error Code | Recommended Action | | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `payment_intent_invalid_currency` | Enter the appropriate currency. Cash App Pay only supports `usd`. | | `missing_required_parameter` | Check the error message for more information about the required parameter. | | `payment_intent_payment_attempt_failed` | This code can appear in the [last_payment_error.code](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-last_payment_error-code) field of a PaymentIntent. Check the error message for a detailed failure reason and suggestion on error handling. | | `payment_intent_redirect_confirmation_without_return_url` | Provide a `return_url` when confirming a PaymentIntent with Cash App Pay. |