Build a custom checkout page that includes Link
This guide describes how to accept payments with Link using information your customer stores in the Link app.
To add Link to your Elements integration, you need to collect a customer’s email address so they can authenticate to Link. You can use the Link Authentication Element to collect email, which Stripe recommends because it allows you to use a single email field for customer email collection and Link authentication during payment.
If you previously collected email ahead of payment (in a previous account creation step for example), or if you prefer to use your own email input field, then you can pass that email into the Payment Element. In this scenario, a customer authenticates to Link directly in the payment form (versus in a separate UI component).
In addition to email, if you’ve previously collected other information from a customer, such as name or phone number, you can optionally pre-fill parts of the payment form to further streamline the checkout process and reduce manual data entry.
Set up StripeServer-side
First, create a Stripe account or sign in.
Use our official libraries to access the Stripe API from your application:
Create a PaymentIntentServer-side
Stripe uses a PaymentIntent object to represent your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process.
Retrieve the client secret
Included in the returned PaymentIntent is a client secret, which the client side uses to securely complete the payment process instead of passing the entire PaymentIntent object. You can use different approaches to pass the client secret to the client side.
Collect customer email
Link authenticates customer accounts using their email address. Use the Link Authentication Element, an email input Element, to both collect a customer’s email during the payment process and enable your customer to authenticate to Link.
If you previously collected email ahead of the payment process or prefer to use your own email input field, you can pass a customer’s email into the Payment Element. In this scenario, you only integrate the Payment Element, and a customer authenticates to Link directly in the payment form.
Set up your payment formClient-side
Now you can set up your custom payment form with the Elements prebuilt UI components.
Note
The payment page address must start with https://
rather than http://
for your integration to work. You can test your integration without using HTTPS. Enable HTTPS when you’re ready to accept live payments.
Submit the payment to StripeClient-side
Use stripe.confirmPayment to complete the payment with details collected from your customer in the different Elements forms. Provide a return_url to this function to indicate where Stripe redirects the user after they complete the payment.
Your user might be first redirected to an intermediate site, like a bank authorization page, before Stripe redirects them to the return_url
.
By default, card and bank payments immediately redirect to the return_url
when a payment is successful. If you don’t want to redirect to the return_url
, you can use if_required
to change the behavior.
The return_url
corresponds to a page on your website that provides the payment status of the PaymentIntent
when you render the return page. When Stripe redirects the customer to the return_url
, you can use the following URL query parameters to verify payment status. You can also append your own query parameters when providing the return_url
. These query parameters persist through the redirect process.
Parameter | Description |
---|---|
payment_intent | The unique identifier for the PaymentIntent |
payment_intent_client_secret | The client secret of the PaymentIntent object. |
Handle post-payment eventsServer-side
Stripe sends a payment_intent.succeeded event when the payment completes. Use a webhook 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.
Configure your integration to listen for these events rather than waiting on a callback from the client. When you wait on a callback from the client, the customer can close the browser window or quit the app before the callback executes. Setting up your integration to listen for asynchronous events enables you to accept different types of payment methods with a single integration.
In addition to handling the payment_intent.succeeded
event, you can also handle two other important events when collecting payments with the Payment Element:
Event | Description | Action |
---|---|---|
payment_intent.succeeded | Sent from Stripe when a customer has successfully completed a payment. | Send the customer an order confirmation and fulfill their order. |
payment_intent.payment_failed | Sent from Stripe when a customer attempted a payment, but the payment didn’t succeed. | If a payment transitioned from processing to payment_failed , offer the customer another attempt to pay. |
Set a cookie to authenticate customersServer-side
You can persist a Link session for your customers and automatically log them in to Link, without additional authentication. This works automatically for browsers that support persistent third-party local storage, such as Chrome and Firefox. For browsers that don’t, like Safari, you can enable persistent sessions in the following steps:
- Retrieve a
persistent_token
from the PaymentIntent after an attempt to confirm it:
- To remember the customer across browser sessions, set a cookie with the
persistent_token
value with the HTTP response on the server side:
- When you create the PaymentIntent, pass in the
persistent_token
value as an additional option:
You might need to update the PaymentIntent with the persistent_token
value explicitly if you create the PaymentIntent before involving the customer in confirming the payment later. You might want to use this type of configuration for recurring charges where you contact customers to confirm their payment.
Privacy implications
Caution
You should always check with your legal counsel to understand how to comply with applicable legal obligations regarding cookies.
Based on your integration choice for Link, Stripe either provides a randomly generated value for you to store in a cookie on your domain (for example, on your checkout flow domain) or for storage on a local cache on the Stripe domain (which is also considered a cookie from a legal perspective). Stripe uses these cookies to help remember the end user on that browser for Link.
Make sure that your privacy policy tells your end users about this type of data collection, and also make sure to update your cookie banner accordingly after reviewing the cookies placed on your website. If your privacy policy doesn’t include this information, consider adding the following paragraph (or something similar) to it:
We use Stripe for payment, analytics, and other business services. Stripe collects identifying information about the devices that connect to its services, including via cookies. Stripe uses this information to operate and improve the services it provides to us, including for fraud detection. You can learn more about Stripe and read its privacy policy at https://stripe.com/privacy.
Test the integration
Caution
Don’t store real user data in test mode Link accounts. Treat them as if they’re publicly available, because these test accounts are associated with your publishable key.
Currently, Link only works with credit cards, debit cards, and qualified US bank account purchases. Link requires domain registration.
You can create test mode accounts for Link using any valid email address. The following table shows the fixed one-time passcode values that Stripe accepts for authenticating test mode accounts:
Value | Outcome |
---|---|
Any other 6 digits not listed below | Success |
000001 | Error, code invalid |
000002 | Error, code expired |
000003 | Error, max attempts exceeded |
For testing specific payment methods, refer to the Payment Element testing examples.
Multiple funding sources
As Stripe adds additional funding source support, you don’t need to update your integration. Stripe automatically supports them with the same transaction settlement time and guarantees as card and bank account payments.
Card authentication and 3D Secure
Link supports 3D Secure 2 (3DS2) authentication for card payments. 3DS2 requires customers to complete an additional verification step with the card issuer when paying. Payments that have been successfully authenticated using 3D Secure are covered by a liability shift.
To trigger 3DS2 authentication challenge flows with Link in test mode, use the following test card with any CVC, postal code, and future expiration date: .
In test mode, the authentication process displays a mock authentication page. On that page, you can either authorize or cancel the payment. Authorizing the payment simulates successful authentication and redirects you to the specified return URL. Clicking the Failure button simulates an unsuccessful attempt at authentication.
For more details, refer to the 3D Secure authentication page.
Note
When testing 3DS flows, only test cards for 3DS2 will trigger authentication on Link.
You can accept payments with Link using information your customer stores in the Link app. When you receive a payment from a customer using Link in the Payment Element, the payment_method.type
listed for the payment is link
.