# Accept an Afterpay or Clearpay payment Learn how to accept Afterpay (also known as Clearpay in the UK), a payment method in the US, CA, UK, AU, and NZ. > The content of this section refers to a *Legacy* (Technology that's no longer recommended) product. You should use the [Accept a payment](https://docs.stripe.com/payments/accept-a-payment.md) guide for the most recent integration path instead. While Stripe still supports this product, this support might end if the product is deprecated. Stripe users can use the [Payment Intents API](https://docs.stripe.com/payments/payment-intents.md)—a single integration path for creating payments using any supported method—to accept [Afterpay](https://www.afterpay.com/) payments from customers in the following countries: - Australia - Canada - New Zealand - United Kingdom - United States Afterpay is a [single use](https://docs.stripe.com/payments/payment-methods.md#usage), [immediate notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method that requires customers to [authenticate](https://docs.stripe.com/payments/payment-methods.md#customer-actions) their payment. Customers are redirected to the Afterpay site, where they agree to the terms of an installment plan. When the customer accepts the terms, funds are guaranteed and transferred to your Stripe account. The customer repays Afterpay directly over time. > Before you start the integration, make sure your account is eligible for Afterpay by navigating to your [Payment methods settings](https://dashboard.stripe.com/settings/payment_methods). ## 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. First, create a `PaymentIntent` on your server and specify the amount to collect and the currency. You can manage payment methods from the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. Make sure that you enable Afterpay / Clearpay in the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]=true" \ -d "shipping[name]=Jenny Rosen" \ -d "shipping[address][line1]=1234 Main Street" \ -d "shipping[address][city]=San Francisco" \ -d "shipping[address][state]=CA" \ -d "shipping[address][country]=US" \ -d "shipping[address][postal_code]=94111" ``` ### 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 frontend framework like 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 ``` ### Improve payment success rates with additional details Optionally, pass [shipping](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-shipping) details to improve conversion rates. In this integration, pass shipping details from the client after your customer selects a payment method. If you send a shipping address, it must include valid values for `line1`, `city`, `state`, `postal_code`, and `country`. ### Additional payment method options You can specify an optional `reference` parameter in the [payment method options](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-payment_method_options-afterpay_clearpay-reference) for your `PaymentIntent` that sets an internal order identifier for the payment. Although this isn’t typically visible to either the business or the consumer, Afterpay’s internal support team can access it during manual support requests. The identifier is limited to 128 characters and might contain only letters, digits, underscores, backslashes, and dashes. #### curl ```bash curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -d "amount"=1099 \ -d "currency"="usd" \ -d "automatic_payment_methods[enabled]"=true \ // Shipping address is optional but recommended to pass in. -d "shipping[name]"="Jenny Rosen" \ -d "shipping[address][line1]"="1234 Main Street" \ -d "shipping[address][city]"="San Francisco" \ -d "shipping[address][state]"="CA" \ -d "shipping[address][country]"="US" \ -d "shipping[address][postal_code]"=94111 \ -d "payment_method_options[afterpay_clearpay][reference]"="order_123" ``` ## Submit the payment to Stripe [Client-side] In this step, you’ll complete Afterpay payments on the client with [Stripe.js](https://docs.stripe.com/payments/elements.md). ### Set up Stripe.js When a customer clicks to pay with Afterpay, we recommend using Stripe.js to submit the payment to Stripe. Stripe.js is our foundational JavaScript library for building payment flows. It automatically handles complexities like the redirect described below, and enables you to easily extend your integration to other payment methods in the future. 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 var stripe = Stripe( '<>', ); ``` Rather than sending the entire PaymentIntent object to the client, use its [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) from [step 2](https://docs.stripe.com/payments/afterpay-clearpay/accept-a-payment.md#web-create-payment-intent). This is different from your API keys that authenticate Stripe API requests. You should still handle the client secret carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer. Use [stripe.confirmAfterpayClearpayPayment](https://docs.stripe.com/js/payment_intents/confirm_afterpay_clearpay_payment) to handle the redirect away from your page and to complete the payment. Add a [return_url](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-return_url) to this function to specify where Stripe redirects the user after they complete the payment on the Afterpay website or mobile application. ```javascript // Redirects away from the client const {error} = await stripe.confirmAfterpayClearpayPayment( '{{PAYMENT_INTENT_CLIENT_SECRET}}', { payment_method: { billing_details: { email: 'jenny@rosen.com', name: 'Jenny Rosen', address: { line1: '1234 Main Street', city: 'San Francisco', state: 'CA', country: 'US', postal_code: '94111', }, }, }, return_url: 'https://example.com/checkout/complete', } ); if (error) { // Inform the customer that there was an error. } ``` When your customer submits a payment, Stripe redirects them to the `return_url` and includes the following URL query parameters. The return page can use them to get the status of the PaymentIntent so it can display the payment status to the customer. When you specify the `return_url`, you can also append your own query parameters for use on the return page. | Parameter | Description | | --- | --- | | `payment_intent` | The unique identifier for the `PaymentIntent`. | | `payment_intent_client_secret` | The [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) of the `PaymentIntent` object. For subscription integrations, this client_secret is also exposed on the `Invoice` object through [`confirmation_secret`](https://docs.stripe.com/api/invoices/object.md#invoice_object-confirmation_secret) | When the customer is redirected back to your site, you can use the `payment_intent_client_secret` to query for the PaymentIntent and display the transaction status to your customer. ## Optional: Add line items to the PaymentIntent You can optionally accept line item data to provide more risk signals to Afterpay. This feature is currently in private beta. Contact us using the form at [Stripe support](https://support.stripe.com) if you want to request access. ## Optional: Separate authorization and capture Unlike [separate authorization and capture for card payments](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md), Afterpay charges the customer the first installment of the payment at the time of authorization. You then have up to 13 days after authorization to capture the rest of the payment. If you don’t capture the payment in this window, the customer receives a refund of the first installment, and they aren’t charged for any further installments. In these cases, Stripe also cancels the PaymentIntent and sends a [payment_intent.canceled](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.canceled) event. If you know that you can’t capture the payment, we recommend [canceling the PaymentIntent](https://docs.stripe.com/refunds.md#cancel-payment) instead of waiting for the 13-day window to elapse. Proactively canceling the PaymentIntent immediately refunds the first installment to your customer, avoiding any confusion about charges on their statement. ### 1. Tell Stripe to authorize only To indicate that you want separate authorization 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 authorize the amount on the customer’s Afterpay account. #### curl ```bash curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -d "amount"=1099 \ -d "currency"="usd" \ -d "automatic_payment_methods[enabled]"="true" \ -d "capture_method"="manual" \ -d "shipping[name]"="Jenny Rosen" \ -d "shipping[address][line1]"="1234 Main Street" \ -d "shipping[address][city]"="San Francisco" \ -d "shipping[address][state]"="CA" \ -d "shipping[address][country]"="US" \ -d "shipping[address][postal_code]"=94111 ``` Upon authorization success, Stripe sends a [payment_intent.amount_capturable_updated](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.amount_capturable_updated) event. Check out our [Events guide](https://docs.stripe.com/api/events.md) for how it may help. ### 2. Capture the funds After the authorization succeeds, the PaymentIntent [status](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-status) transitions to `requires_capture`. To capture the authorized funds, make a PaymentIntent [capture](https://docs.stripe.com/api/payment_intents/capture.md) request. The total authorized amount is captured by default—you can’t capture more than this, but you can capture less. ```curl curl https://api.stripe.com/v1/payment_intents/{{PAYMENTINTENT_ID}}/capture \ -u "<>:" \ -d amount_to_capture=750 ``` ### (Optional) Cancel the authorization If you need to cancel an authorization, you can [cancel the PaymentIntent](https://docs.stripe.com/refunds.md#cancel-payment). ## Optional: Handle the Afterpay redirect manually We recommend relying on Stripe.js to handle Afterpay redirects and payments client-side with `confirmAfterpayClearpayPayment`. Using Stripe.js helps extend your integration to other payment methods. However, you can also manually redirect your customers on your server by following these steps: - Create and confirm a [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) of type `afterpay_clearpay`. You must provide the `payment_method_data.billing_details` property that is required by Afterpay. `payment_intent.shipping` is optional but recommended for improved authentication rates. By specifying `payment_method_data`, Stripe creates a *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) and immediately uses it with this PaymentIntent. You must also provide the redirect URL for your customer after they complete their payment in the `return_url` field. You can also provide your own query parameters in this URL. These parameters are included in the final URL upon completing the redirect flow. #### curl ```bash curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -d "amount"=1099 \ -d "currency"="usd" \ -d "confirm"="true" \ -d "shipping[name]"="Jenny Rosen" \ -d "shipping[address][line1]"="1234 Main Street" \ -d "shipping[address][city]"="San Francisco" \ -d "shipping[address][state]"="CA" \ -d "shipping[address][country]"="US" \ -d "shipping[address][postal_code]"=94111 \ -d "payment_method_data[billing_details][name]"="Jenny Rosen" \ -d "payment_method_data[billing_details][email]"="jenny@example.com" \ -d "payment_method_data[billing_details][address][line1]"="1234 Main Street" \ -d "payment_method_data[billing_details][address][city]"="San Francisco" \ -d "payment_method_data[billing_details][address][state]"="CA" \ -d "payment_method_data[billing_details][address][country]"="US" \ -d "payment_method_data[billing_details][address][postal_code]"=94111 \ -d "payment_method_data[type]"="afterpay_clearpay" \ -d "return_url"="https://example.com/checkout/complete" ``` The created `PaymentIntent` has a status of `requires_action` and the type for `next_action` is `redirect_to_url`. #### Json ```json { "status": "requires_action", "next_action": { "type": "redirect_to_url", "redirect_to_url": { "url": "https://hooks.stripe.com/...", "return_url": "https://example.com/checkout/complete" } }, "id": "pi_1G1sgdKi6xqXeNtkldRRE6HT", "object": "payment_intent", "amount": 1099, "client_secret": "pi_1G1sgdKi6xqXeNtkldRRE6HT_secret_h9B56ObhTN72fQiBAuzcVPb2E", "confirmation_method": "automatic", "created": 1579259303, "currency": "usd", "livemode": true, "charges": { "data": [], "object": "list", "has_more": false, "url": "/v1/charges?payment_intent=pi_1G1sgdKi6xqXeNtkldRRE6HT" }, "payment_method_options": { "afterpay_clearpay": {} }, "payment_method_types": [ "afterpay_clearpay" ] } ``` - Redirect the customer to the URL provided in the `next_action.redirect_to_url.url` property. The code example here is approximate—the redirect method might be different in your web framework. #### Ruby ```ruby if payment_intent.status == 'requires_action' && payment_intent.next_action.type == 'redirect_to_url' url = payment_intent.next_action.redirect_to_url.url redirect(url) end ``` When the customer finishes the payment process, they’re sent to the `return_url` configured in step 1. The `payment_intent` and `payment_intent_client_secret` URL query parameters are included and you can pass through your own query parameters, as described above. We recommend that you [rely on webhooks](https://docs.stripe.com/payments/payment-intents/verifying-status.md#webhooks) to confirm the status of a payment. ## 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. ## Optional: Test Afterpay integration Test your Afterpay integration with your test API keys by viewing the redirect page. You can test a successful payment by authenticating the payment on the redirect page. The PaymentIntent will transition from `requires_action` to `succeeded`. To test authentication failure, use your test API keys and view the redirect page. On the redirect page, click **Fail test payment**. The PaymentIntent will transition from `requires_action` to `requires_payment_method`. For [manual capture](https://docs.stripe.com/payments/afterpay-clearpay/accept-a-payment.md#manual-capture) PaymentIntents in testmode, the uncaptured PaymentIntent will auto-expire 10 minutes after successful authorization. ## Optional: Display payment method messaging on your website The [Payment Method Messaging Element](https://docs.stripe.com/js/elements_object/create_element?type=paymentMethodMessaging) is an embeddable UI component that helps your customers know which buy now, pay later payment options they have at checkout directly from your product, cart, or payment pages. To add the Payment Method Messaging Element to your website, see [Display payment method messaging](https://docs.stripe.com/elements/payment-method-messaging.md). ## Failed payments Afterpay takes into account multiple factors when deciding to accept or decline a transaction (for example, the length of time the customer has been using Afterpay, the outstanding amount the customer has to repay, or the value of the current order). You should always present additional payment options such as `card` in your checkout flow, as Afterpay payments have a higher rate of decline than many payment methods. 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`. For an Afterpay [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) with a status of `requires_action`, customers need to complete the payment within 3 hours after you redirect them to the Afterpay site (this doesn’t apply to declined payments). If they take no action within 3 hours, the [PaymentMethod](https://docs.stripe.com/api/payment_methods/object.md) detaches and the object status for the [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) automatically transitions to `requires_payment_method`. In these cases, inform your customer to try again with a different payment option presented in your checkout flow. ## Error codes These are the common error codes and corresponding recommended actions: | Error code | Recommended action | | --- | --- | | `payment_intent_payment_attempt_failed` | A generic failure indicating the Afterpay checkout failed. This can also be a decline which doesn’t appear as a decline error code. | | `payment_method_provider_decline` | Afterpay declined the customer’s payment. As a next step, the customer needs to contact Afterpay for more information. | | `payment_intent_payment_attempt_expired` | The customer never completed the payment on Afterpay’s checkout page, and the payment session has expired. Stripe automatically expires PaymentIntents that aren’t successfully authorized 3 hours after initial checkout creation. | | `payment_method_not_available` | Afterpay experienced a service related error and is unable to complete the request. Retry at a later time. | | `amount_too_small` | Enter an amount within Afterpay’s [default transactions limits](https://docs.stripe.com/payments/afterpay-clearpay.md#collection-schedule) for the country. | | `amount_too_large` | Enter an amount within Afterpay’s [default transactions limits](https://docs.stripe.com/payments/afterpay-clearpay.md#collection-schedule) for the country. |