Skip to content
Create account or Sign in
The Stripe Docs logo
/
Ask AI
Create accountSign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
APIs & SDKsHelp
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseUse Managed Payments
Use Payment Links
Use a prebuilt checkout page
Build a custom integration with Elements
Build an in-app integration
In-person payments
Terminal
Payment methods
Add payment methods
    Overview
    Payment method integration options
    Manage default payment methods in the Dashboard
    Payment method types
    Cards
    Pay with Stripe balance
    Stablecoin payments
    Bank debits
    Bank redirects
    Bank transfers
    Credit transfers (Sources)
    Buy now, pay later
      Affirm
      Afterpay / Clearpay
        Accept a payment
        Site messaging
      Alma
      Billie
      Capchase Pay
      Klarna
      Kriya
      Mondu
      Payment on Invoice
      Scalapay
      SeQura
      Sunbit
      Zip
    Real-time payments
    Vouchers
    Wallets
    Enable local payment methods by country
    Custom payment methods
Manage payment methods
Faster checkout with Link
Payment scenarios
Handle multiple currencies
Custom payment flows
Flexible acquiring
Orchestration
Beyond payments
Incorporate your company
Crypto
Agentic commerce
Financial Connections
Climate
Understand fraud
Radar fraud protection
Manage disputes
Verify identities
United States
English (United States)
HomePaymentsAdd payment methodsBuy now, pay laterAfterpay / Clearpay

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.

Caution

The content of this section refers to a Legacy product. You should use the Accept a payment 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—a single integration path for creating payments using any supported method—to accept Afterpay payments from customers in the following countries:

  • Australia
  • Canada
  • New Zealand
  • United Kingdom
  • United States

Afterpay is a single use, immediate notification payment method that requires customers to authenticate 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.

Note

Before you start the integration, make sure your account is eligible for Afterpay by navigating to your Payment methods settings.

Set up Stripe
Server-side
Client-side

Server-side

This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries for access to the Stripe API from your server:

Command Line
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# Available as a gem sudo gem install stripe
Gemfile
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Client-side

The React Native SDK is open source and fully documented. Internally, it uses the native iOS and Android SDKs. To install Stripe’s React Native SDK, run one of the following commands in your project’s directory (depending on which package manager you use):

Command Line
yarn add @stripe/stripe-react-native

Next, install some other necessary dependencies:

  • For iOS, go to the ios directory and run pod install to ensure that you also install the required native dependencies.
  • For Android, there are no more dependencies to install.

Note

We recommend following the official TypeScript guide to add TypeScript support.

Stripe initialization

To initialize Stripe in your React Native app, either wrap your payment screen with the StripeProvider component, or use the initStripe initialization method. Only the API publishable key in publishableKey is required. The following example shows how to initialize Stripe using the StripeProvider component.

import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( <StripeProvider publishableKey={publishableKey} merchantIdentifier="merchant.identifier" // required for Apple Pay urlScheme="your-url-scheme" // required for 3D Secure and bank redirects > {/* Your app code here */} </StripeProvider> ); }

Note

Use your API test keys while you test and develop, and your live mode keys when you publish your app.

Create a PaymentIntent
Server-side
Client-side

A PaymentIntent is an object that represents your intent to collect payment from a customer and tracks the lifecycle of the payment process through each stage.

Server-side

First, create a PaymentIntent on your server and specify the amount to collect and the currency. If you already have an integration using the Payment Intents API, add afterpay_clearpay to the list of payment method types for your PaymentIntent.

Command Line
curl
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:
\ -d "amount"=1099 \ -d "currency"="usd" \ -d "payment_method_types[]"="afterpay_clearpay"

Client-side

Included in the returned PaymentIntent is a client secret, which the client side can use to securely complete the payment process instead of passing the entire PaymentIntent object. On the client, request a PaymentIntent from your server and store its client secret.

const fetchPaymentIntentClientSecret = async () => { const response = await fetch(`${API_URL}/create-payment-intent`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ currency: 'usd', payment_method_types: ['afterpay_clearpay'], }), }); const {clientSecret, error} = await response.json(); return {clientSecret, error}; };

Collect payment method details
Client-side

Afterpay requires billing details to be present for the payment to succeed. In your app, collect the required billing details from the customer:

  • Full name (first and last)
  • Email address
  • Full billing address

Additionally, while shipping details aren’t required they can help improve authentication rates. To collect shipping details, collect the following from the customer:

  • Full name
  • Full shipping address
export default function AfterpayClearpayPaymentScreen() { const [email, setEmail] = useState(''); const handlePayPress = async () => { const billingDetails: PaymentMethodCreateParams.BillingDetails = { email, phone: '+48888000888', addressCity: 'Houston', addressCountry: 'US', addressLine1: '1459 Circle Drive', addressLine2: 'Texas', addressPostalCode: '77063', name: 'Jenny Rosen', }; // Shipping details are optional but recommended to pass in. const shippingDetails: PaymentMethodCreateParams.ShippingDetails = { addressLine1: '1459 Circle Drive', addressCountry: 'US', addressPostalCode: '77063', name: 'Jenny Rosen', }; // ... }; return ( <Screen> <TextInput placeholder="E-mail" onChange={(value) => setEmail(value.nativeEvent.text)} /> </Screen> ); }

Submit the payment to Stripe
Client-side

Retrieve the client secret from the PaymentIntent you created and call confirmPayment. 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.

export default function AfterpayClearpayPaymentScreen() { const [email, setEmail] = useState(''); const handlePayPress = async () => { // ... const {error, paymentIntent} = await confirmPayment(clientSecret, { paymentMethodType: 'AfterpayClearpay', paymentMethodData: { billingDetails, // Shipping details are optional but recommended to pass in. shippingDetails, }, }); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { Alert.alert( 'Success', `The payment was confirmed successfully! currency: ${paymentIntent.currency}`, ); } }; return <Screen>{/* ... */}</Screen>; }

OptionalHandle deep linking

When a customer exits your app (for example to authenticate in Safari or their banking app), provide a way for them to automatically return to your app. Many payment method types require a return URL. If you don’t provide one, we can’t present payment methods that require a return URL to your users, even if you’ve enabled them.

To provide a return URL:

  1. Register a custom URL. Universal links aren’t supported.
  2. Configure your custom URL.
  3. Set up your root component to forward the URL to the Stripe SDK as shown below.

Note

If you’re using Expo, set your scheme in the app.json file.

App.tsx
import { useEffect, useCallback } from 'react'; import { Linking } from 'react-native'; import { useStripe } from '@stripe/stripe-react-native'; export default function MyApp() { const { handleURLCallback } = useStripe(); const handleDeepLink = useCallback( async (url: string | null) => { if (url) { const stripeHandled = await handleURLCallback(url); if (stripeHandled) { // This was a Stripe URL - you can return or add extra handling here as you see fit } else { // This was NOT a Stripe URL – handle as you normally would } } }, [handleURLCallback] ); useEffect(() => { const getUrlAsync = async () => { const initialUrl = await Linking.getInitialURL(); handleDeepLink(initialUrl); }; getUrlAsync(); const deepLinkListener = Linking.addEventListener( 'url', (event: { url: string }) => { handleDeepLink(event.url); } ); return () => deepLinkListener.remove(); }, [handleDeepLink]); return ( <View> <AwesomeAppComponent /> </View> ); }

For more information on native URL schemes, refer to the Android and iOS docs.

OptionalAdd 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. To request access, contact us.

OptionalSeparate authorization and capture

Unlike separate authorization and capture for card payments, 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 event.

If you know that you can’t capture the payment, we recommend canceling the PaymentIntent 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 to manual when creating the PaymentIntent. This parameter instructs Stripe to only authorize the amount on the customer’s Afterpay account.

Command Line
curl
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:
\ -d "amount"=1099 \ -d "currency"="usd" \ -d "payment_method_types[]"="afterpay_clearpay" \ -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 event. Check out our Events guide for how it may help.

2. Capture the funds

After the authorization succeeds, the PaymentIntent status transitions to requires_capture. To capture the authorized funds, make a PaymentIntent capture request. The total authorized amount is captured by default—you can’t capture more than this, but you can capture less.

Command Line
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl https://api.stripe.com/v1/payment_intents/
{{PAYMENT_INTENT_ID}}
/capture
\ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount_to_capture=750

Optional Cancel the authorization

If you need to cancel an authorization, you can cancel the PaymentIntent.

OptionalHandle post-payment events

Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, 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.

  • Handle events manually in the Dashboard

    Use the Dashboard to View your test payments in the Dashboard, send email receipts, handle payouts, or retry failed payments.

  • Build a custom webhook

    Build a custom 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 or marketing and sales, by integrating a partner application.

OptionalTest Afterpay integration

Test your Afterpay integration with your test API keys by viewing the redirect page. You can test the successful payment case by authenticating the payment on the redirect page. The PaymentIntent will transition from requires_action to succeeded.

To test the case where the user fails to authenticate, 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 PaymentIntents in testmode, the uncaptured PaymentIntent will auto-expire 10 minutes after successful authorization.

Failed payments

Afterpay takes into account multiple factors when deciding to accept or decline a transaction (for example, length of time buyer has been using Afterpay, outstanding amount customer has to repay, 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 is detached and the PaymentIntent object’s status automatically transitions to requires_payment_method.

For an Afterpay PaymentIntent 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 detaches and the object status for the PaymentIntent 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 codeRecommended action
payment_intent_payment_attempt_failedA generic failure indicating the Afterpay checkout failed. This can also be a decline which does not appear as a decline error code.
payment_method_provider_declineAfterpay declined the customer’s payment. As a next step, the customer needs to contact Afterpay for more information.
payment_intent_payment_attempt_expiredThe 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_availableAfterpay experienced a service related error and is unable to complete the request. Retry at a later time.
amount_too_smallEnter an amount within Afterpay’s default transactions limits for the country.
amount_too_largeEnter an amount within Afterpay’s default transactions limits for the country.
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc