Searched, saw the right answer, and answered against it. Unaided belief: wrong. With tools: searched on 100% of samples, answered correctly on 0%.
98 By default, Stripe enables cards and other common payment methods. You can turn individual payment methods on or off in the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods). In Checkout, Stripe evaluates the currency and any restrictions, then dynamically presents the supported payment methods to the customer.
99 To see how your payment methods appear to customers, enter a transaction ID or set an order amount and currency in the Dashboard’s [payment methods review](https://dashboard.stripe.com/settings/payment_methods/review) page.
100 Checkout supports Apple Pay and Google Pay with no integration changes. Learn how to [test wallets](https://docs.stripe.com/testing/wallets?ui=embedded-page).
101 ### Verify your integration
102 You should now have a working checkout button that redirects your customer to Stripe Checkout.
| WRONG | For **Stripe-hosted Checkout**, you usually don’t need a separate Apple Pay or Google Pay integration. Both wallets are presented as wallet options for the `card` payment method when the customer and transaction qualify.
### 1. Enable the relevant payment methods in Stripe
In the Stripe Dashboard, go to:
**Settings → Payment methods**
Make sure **Cards**, **Apple Pay**, and **Google Pay** are enabled. Stripe may show the wallets as part of the card payment method rather than as standalone methods.
### 2. Keep `card` enabled in your Checkout Session
For example:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancel',
payment_method_types: ['card'],
});
```
Apple Pay and Google Pay can appear through `card`. Do **not** add them as:
```js
payment_method_types: ['apple_pay', 'google_pay']
```
Those are not normally specified as separate Checkout payment method types.
Alternatively, allow Stripe to manage eligible methods dynamically:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
// Omit payment_method_types to use Dashboard-configured methods
});
```
### 3. Make sure your testing conditions support the wallets
The wallet buttons only appear when appropriate:
- **Apple Pay:** Safari on a supported Apple device with Apple Pay set up
- **Google Pay:** supported Chrome/Android environment with Google Pay set up
- Your site should use **HTTPS**
- The customer must have an eligible card and supported country/currency
- The transaction amount and business location must be supported
For Stripe-hosted Checkout, you generally do **not** need to create your own Apple merchant ID or register your domain manually. That is typically required when using Apple Pay through Stripe Elements or the Payment Request Button, not standard hosted Checkout.
### 4. Don’t change fulfillment logic
Apple Pay and Google Pay payments still complete through Checkout in the same way as other payments. Fulfill orders from a webhook such as:
```text
checkout.session.completed
```
rather than relying only on the success-page redirect.
If you are using **Stripe Elements, Payment Element, or a custom checkout form** instead of hosted Checkout, the setup is different: you may need an Express Checkout Element, domain registration for Apple Pay, and additional wallet configuration. It says to enable and configure payment methods and keep `card` enabled, whereas the source states that Stripe Checkout accepts Apple Pay and Google Pay with no integration changes. |
| WRONG | ## If you use Stripe-hosted Checkout
Usually, **no code changes are required**. Stripe Checkout can display Apple Pay and Google Pay automatically when the customer’s device, browser, wallet, currency, and region are eligible.
Make sure that:
1. **Apple Pay and Google Pay are enabled** in the Stripe Dashboard under **Settings → Payment methods**.
2. Your Checkout Session uses automatic payment methods, or at least allows cards:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
// Usually optional with modern Checkout integrations:
automatic_payment_methods: {
enabled: true,
},
});
```
If your integration explicitly restricts payment methods, remove the restriction or ensure cards are enabled:
```js
payment_method_types: ['card']
```
Apple Pay and Google Pay transactions are generally processed through the `card` payment method in Checkout. You do not create separate PaymentIntents or separate fulfillment logic for them.
## If you use embedded Checkout or Elements
You must also register every domain where the wallet button can appear:
- Production domain
- `www` and non-`www` variants, if applicable
- Any checkout subdomains
- Staging/test domains, if you test there
Register them in Stripe under the payment-method domain settings, or via Stripe’s payment-method domain API. The site must use HTTPS.
For a custom Elements integration, use the **Express Checkout Element**:
```js
const expressCheckout = elements.create('expressCheckout', {
wallets: {
applePay: 'auto',
googlePay: 'auto',
},
});
expressCheckout.mount('#express-checkout-element');
```
With Express Checkout Element, also register the domains that display the element.
## Important eligibility requirements
The buttons only appear when the customer is eligible:
- **Apple Pay:** supported Apple device/browser, Apple Pay configured, HTTPS
- **Google Pay:** supported browser/device, Google Wallet configured, HTTPS
- Customer’s country, currency, card network, and Stripe account configuration must support the wallet
- The wallet must be enabled in Stripe
- Embedded integrations must have their domains registered
You should not expect the buttons to appear for every browser or test environment.
## Testing
Use Stripe’s wallet testing guidance and test on real eligible environments:
- Apple Pay in Safari with a test Apple Pay setup
- Google Pay in a supported Chrome/Android environment
- Stripe test mode with the appropriate test wallet setup
Your existing webhook and payment-confirmation flow should continue to work. Continue fulfilling orders from events such as `checkout.session.completed` or the relevant payment event, rather than relying only on the client-side success redirect.
References:
- [Stripe Checkout payment methods](https://docs.stripe.com/payments/payment-method-configurations)
- [Register domains for payment methods](https://docs.stripe.com/payments/payment-methods/pmd-registration)
- [Express Checkout Element](https://docs.stripe.com/elements/express-checkout-element)
- [Stripe wallet testing](https://docs.stripe.com/testing/wallets) Although it initially says no code changes are usually required, it asserts that enabling wallets, configuring payment methods, and in some cases registering domains are required changes, conflicting with the source's unqualified statement that Checkout supports both wallets with no integration changes. site:docs.stripe.com/payments/checkout Apple Pay Google Pay Checkout integration enable wallets5 results
results as cached 2026-09-14T15:05 site:docs.stripe.com/payments/wallets Apple Pay Google Pay domain registration Stripe Checkout0 results
results as cached 2026-09-14T15:05 site:docs.stripe.com/checkout express checkout element Apple Pay Google Pay0 results
results as cached 2026-09-14T15:05 Stripe Checkout Apple Pay Google Pay no integration changes automatic payment methods docs5 results
results as cached 2026-09-14T15:05 Stripe enable Apple Pay Google Pay Dashboard payment methods Checkout domain registration5 results
results as cached 2026-09-14T15:05 Stripe Express Checkout Element wallets Apple Pay Google Pay domain registration5 results
results as cached 2026-09-14T15:05 |
Searched, your content never reached it, and it answered wrongly anyway. Unaided belief: correct. With tools: searched on 100% of samples, answered correctly on 0%.
133 To test your Stripe-hosted payment form integration: 134 1. Create a Checkout Session. 135 2. Fill out the payment details with a method from the following table. 136 * Enter any future date for card expiry. 137 * Enter any 3-digit number for CVC. 138 * Enter any billing postal code. 139 3. Click **Pay**. You’re redirected to your `success_url`. 140 4. Go to the Dashboard and look for the payment on the [Transactions page](https://dashboard.stripe.com/test/payments?status%5B0%5D=successful). If your payment succeeded, you’ll see it in that list.
| CORRECT | For Stripe Checkout in **test mode**, you can use:
- **Card number:** `4242 4242 4242 4242`
- **Expiry date:** Any future date, e.g. `12/34`
- **CVC:** Any 3-digit number, e.g. `123`
- **Postal code:** Any valid-looking postal code, e.g. `12345`
Use only Stripe’s test mode—never enter real card details. It states any future expiry date, any three-digit CVC, and a postal code, consistent with the source's requirements. |
| WRONG | For Stripe Checkout in **test mode**, use:
- **Expiry date:** Any valid future date, e.g. `12/34`
- **CVC:** Any 3-digit number, e.g. `123`
- For American Express, use 4 digits.
- **Postal code:** Any valid postal code, typically a 5-digit U.S. ZIP code such as `12345`
For example:
```text
Card: 4242 4242 4242 4242
Expiry: 12/34
CVC: 123
Postal code: 12345
```
Use Stripe’s test card numbers only with test API keys; they don’t work for real charges. It says American Express requires a 4-digit CVC, which conflicts with the source’s instruction to enter any 3-digit CVC. site:docs.stripe.com testing test cards expiry date CVC postal code Stripe Checkout5 results
results as cached 2026-09-14T15:05 |
Asserted a confident answer to a question it had no basis to answer. Unaided belief: wrong. With tools: searched on 100% of samples, answered correctly on 0%.
| WRONG | Stripe Checkout can collect a shipping address as part of the hosted checkout page. Configure the countries you support when creating the Checkout Session:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
// Require a shipping address and restrict supported countries.
shipping_address_collection: {
allowed_countries: ['US', 'CA'],
},
// Optional: show shipping methods/rates.
shipping_options: [
{
shipping_rate: 'shr_standard',
},
],
// Optional, if the billing address is also required.
billing_address_collection: 'required',
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cart',
});
```
Stripe will require the customer to enter an address before they can submit payment and will perform basic field and country validation.
### Retrieve the submitted address
Handle the Checkout webhook rather than trusting the success page:
```js
app.post('/stripe-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const event = stripe.webhooks.constructEvent(
req.body,
req.headers['stripe-signature'],
process.env.STRIPE_WEBHOOK_SECRET
);
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
const shipping = session.shipping_details;
const address = shipping?.address;
// Save the address with the order.
// address.country, address.postal_code, address.line1, etc.
}
res.sendStatus(200);
});
```
For asynchronous payment methods, also handle `checkout.session.async_payment_succeeded` before fulfilling the order.
### Custom validation rules
Checkout supports basic validation and an allowed-country list, but it does not provide a general server-side callback that pauses hosted Checkout so your server can approve an arbitrary address before payment. For rules such as:
- postal-code serviceability,
- address matching against your own database,
- restricted regions,
- hazardous-goods delivery rules,
- real-time tax or delivery validation,
use one of these approaches:
1. **Collect and validate the address on your own page first**, then create the Checkout Session only after validation succeeds.
2. **Use Stripe’s embedded/custom payment flow**, such as the Payment Element, where your application controls the address form and can validate it before calling `stripe.confirmPayment`.
3. **Validate after Checkout and before fulfillment**, marking the order for review or refunding it if the address is unacceptable.
Do not rely only on client-side validation or the `success_url`; verify the webhook signature and validate the final address and payment status on your server. The answer gives detailed, confident Stripe-specific implementation guidance despite the source material not answering the question. |
| WRONG | Use Checkout’s built-in shipping-address collection when creating the Checkout Session. Checkout displays the address form and validates the required fields before allowing the customer to submit payment.
### 1. Create the Session server-side
Specify the countries you ship to with `shipping_address_collection.allowed_countries`:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
shipping_address_collection: {
allowed_countries: ['US', 'CA'],
},
// Optional: collect billing address too
billing_address_collection: 'required',
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cart',
});
```
Then redirect the customer to `session.url`.
The allowed countries must be two-letter ISO country codes. Stripe stores the submitted address in the completed Session’s `shipping_details` property. Stripe’s built-in validation checks that the address is structurally complete and compatible with the selected country; it is not necessarily a guarantee that the address physically exists or is deliverable.
Source: [Stripe — Collect physical addresses](https://docs.stripe.com/payments/collect-addresses)
### 2. Retrieve the address from the webhook
Do not rely only on the success URL for fulfillment. Handle `checkout.session.completed` server-side and retrieve or read:
```js
const session = event.data.object;
const shipping = session.shipping_details;
// {
// name: 'Jane Doe',
// address: {
// line1: '...',
// city: '...',
// state: 'CA',
// postal_code: '...',
// country: 'US'
// }
// }
```
Use the webhook to verify the payment status and save the shipping address with the order:
```js
if (
event.type === 'checkout.session.completed' &&
event.data.object.payment_status === 'paid'
) {
const session = event.data.object;
const address = session.shipping_details?.address;
// Save the order and address, then fulfill it.
}
```
Stripe documents that the collected shipping address is available on `shipping_details` and in the `checkout.session.completed` webhook.
Source: [Stripe — Collect physical addresses](https://docs.stripe.com/payments/collect-addresses)
### 3. Apply your own shipping rules before payment
If “validate” means rules such as:
- reject PO boxes,
- validate a postal code against your service area,
- verify an address with a carrier/geocoding provider,
- calculate shipping based on ZIP/postal code,
- restrict certain products to certain regions,
use a Checkout integration that supports dynamic shipping updates—such as Checkout’s embedded form or Elements—and validate the address as it is entered. Based on the result, update the available shipping options or return an error so Checkout prevents completion.
Stripe specifically supports dynamically customizing shipping options based on the customer’s address and validating whether you can ship to it.
Source: [Stripe — Dynamically customize shipping options](https://docs.stripe.com/payments/checkout/custom-shipping-options)
For a fully custom address workflow, collect the address first with Stripe’s [Address Element](https://docs.stripe.com/elements/address-element), send it to your server or address-validation provider, and only then create or confirm the payment flow. The Address Element can also perform client-side field validation when the Checkout Session is confirmed.
### Important distinction
- **Hosted Checkout:** easiest; use `shipping_address_collection`. Stripe validates required address fields before payment, but custom validation generally cannot be performed in the middle of the hosted page.
- **Embedded Checkout/Elements:** supports address-dependent shipping options and custom validation before payment.
- **Webhook:** always perform a final server-side check before fulfillment, even if the address was validated in the browser. Never trust client-submitted address data or the success-page redirect alone. The answer gives detailed, confident implementation guidance despite the source material not providing the information needed to support it. site:docs.stripe.com checkout address validation shipping address5 results
results as cached 2026-09-14T15:05 site:docs.stripe.com checkout shipping_address_collection allowed_countries validate shipping address5 results
results as cached 2026-09-14T15:05 site:docs.stripe.com checkout collect shipping address before payment5 results
results as cached 2026-09-14T15:05 opened 3 pages |
Asserted a confident answer to a question it had no basis to answer. Unaided belief: wrong. With tools: searched on 100% of samples, answered correctly on 0%.
| WRONG | To create a recurring subscription, create a Stripe Checkout Session with:
- `mode: 'subscription'`
- A `line_items` entry that references a **recurring Stripe Price**
- Success and cancellation URLs
### Node.js example
```js
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price: 'price_123456789', // Price configured with a recurring interval
quantity: 1,
},
],
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/canceled',
});
console.log(session.url);
```
Redirect the customer to `session.url`.
### Creating a recurring Price
The referenced Price must be configured as recurring, for example:
```js
const price = await stripe.prices.create({
currency: 'usd',
unit_amount: 2000, // $20.00
recurring: {
interval: 'month',
},
product_data: {
name: 'Monthly Plan',
},
});
```
Then use `price.id` in the Checkout Session.
### Optional subscription settings
You can add subscription-specific options:
```js
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price: 'price_123456789',
quantity: 1,
},
],
subscription_data: {
trial_period_days: 14,
metadata: {
plan: 'pro',
},
},
customer_email: 'customer@example.com',
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/canceled',
});
```
Use webhooks such as `checkout.session.completed`, `customer.subscription.created`, and `customer.subscription.updated` to provision access and track subscription changes. The key difference from a one-time Checkout Session is using `mode: 'subscription'` with a recurring Price. The answer gives specific, confident Stripe implementation instructions despite the source material not providing this information. |
| WRONG | To create a recurring subscription, create a **recurring Price** in Stripe and set the Checkout Session’s `mode` to `"subscription"`.
### Node.js example
```js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price: 'price_123456789', // A recurring Stripe Price
quantity: 1,
},
],
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancel',
});
console.log(session.url);
```
Redirect the customer to `session.url`:
```js
res.redirect(303, session.url);
```
The referenced Price must have recurring billing configured, such as monthly or yearly. For example, a recurring Price might be configured with:
```json
{
"unit_amount": 2000,
"currency": "usd",
"recurring": {
"interval": "month"
}
}
```
You can also create the recurring Price inline:
```js
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price_data: {
currency: 'usd',
product: 'prod_123456789',
unit_amount: 2000,
recurring: {
interval: 'month',
},
},
quantity: 1,
},
],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
});
```
Key differences from a one-time Checkout Session:
- Use `mode: 'subscription'`, not `mode: 'payment'`.
- Use a recurring Price, or provide `price_data.recurring`.
- Stripe creates and manages the Subscription after successful Checkout.
- Handle webhooks such as `checkout.session.completed`, `invoice.paid`, and `invoice.payment_failed` to provision access and respond to billing events.
See Stripe’s [Subscriptions with Checkout Sessions](https://docs.stripe.com/payments/subscriptions) and [Create a Checkout Session API reference](https://docs.stripe.com/api/checkout/sessions/create). The answer gives specific, confident Stripe implementation instructions despite the source material not providing this information. site:docs.stripe.com checkout sessions subscriptions mode subscription recurring price5 results
results as cached 2026-09-14T15:05 site:docs.stripe.com/api/checkout/sessions/create mode subscription line_items price recurring1 result
results as cached 2026-09-14T15:05 |
Asserted a confident answer to a question it had no basis to answer. Unaided belief: wrong. With tools: searched on 100% of samples, answered correctly on 0%.
| WRONG | Stripe Checkout supports discounts in two main ways:
1. **Let the customer enter a promotion code**
2. **Apply a coupon or promotion code automatically from your server**
## 1. Allow customers to enter a promotion code
Create a promotion code in the Stripe Dashboard or API, then enable the Checkout field:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
allow_promotion_codes: true,
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancel',
});
```
Checkout displays a promotion-code input. Stripe validates the code, including its expiration date, redemption limits, customer restrictions, and eligible products.
## 2. Apply a discount automatically
Create a coupon, then either use the coupon directly or create a promotion code from it.
### Apply a coupon
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
discounts: [
{
coupon: 'coupon_123',
},
],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
});
```
### Apply a specific promotion code
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: 'price_123',
quantity: 1,
},
],
discounts: [
{
promotion_code: 'promo_123',
},
],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
});
```
A promotion code is customer-facing and can include restrictions such as:
- A specific code, such as `WELCOME20`
- Expiration date
- Maximum redemptions
- Minimum order amount
- First-time-customer eligibility
- Eligible products or prices
For example, create a coupon and promotion code using the API:
```js
const coupon = await stripe.coupons.create({
percent_off: 20,
duration: 'once',
});
const promotionCode = await stripe.promotionCodes.create({
coupon: coupon.id,
code: 'WELCOME20',
max_redemptions: 100,
});
```
Use either `allow_promotion_codes` for customer-entered codes or `discounts` for a discount selected by your application. Create the Checkout Session on your server and do not trust discount information sent directly from the browser.
For subscriptions, the same Checkout Session options apply; the coupon’s duration determines whether the discount applies once, for a number of billing cycles, or indefinitely. The answer gives detailed, confident Stripe-specific instructions even though the source material does not provide enough information to support them. |
| WRONG | A Stripe Checkout integration can apply discounts in two main ways:
## 1. Apply a coupon programmatically
Use this when your backend decides that the customer qualifies. Create a coupon in the Dashboard or through the API, then pass its ID in the Checkout Session’s `discounts` array.
```bash
curl https://api.stripe.com/v1/checkout/sessions \
-u "sk_test_...:" \
-d "line_items[0][price]"="{{PRICE_ID}}" \
-d "line_items[0][quantity]"=1 \
-d "discounts[0][coupon]"="{{COUPON_ID}}" \
-d mode=payment \
--data-urlencode "success_url=https://example.com/success" \
--data-urlencode "cancel_url=https://example.com/cancel"
```
Coupons can represent either a percentage discount or a fixed amount, and can be limited to particular products.
## 2. Let customers enter a promotion code
Create a promotion code associated with an existing coupon, then enable the promotion-code field in Checkout:
```bash
curl https://api.stripe.com/v1/checkout/sessions \
-u "sk_test_...:" \
-d "line_items[0][price]"="{{PRICE_ID}}" \
-d "line_items[0][quantity]"=1 \
-d mode=payment \
-d allow_promotion_codes=true \
--data-urlencode "success_url=https://example.com/success" \
--data-urlencode "cancel_url=https://example.com/cancel"
```
With `allow_promotion_codes=true`, Checkout displays a field where the customer can enter a code such as `SAVE20`. Stripe validates the code and applies the associated coupon if it is eligible.
## Coupon vs. promotion code
- **Coupon:** The discount definition—such as 20% off or $10 off.
- **Promotion code:** A customer-facing code that references a coupon and can add restrictions such as:
- Specific eligible customers
- First-time orders only
- Minimum order amount
- Expiration date
- Maximum redemptions
A Checkout Session currently supports up to one coupon or promotion code. For subscriptions, the same `discounts` mechanism can be used, and coupon duration can be configured for one invoice, multiple months, or indefinitely.
Always create Checkout Sessions server-side and keep secret API keys out of client code. See Stripe’s [Checkout discounts documentation](https://docs.stripe.com/payments/checkout/discounts) for the current API details. The answer gives detailed, confident Stripe-specific instructions despite the source material not providing this information. site:docs.stripe.com checkout promotion codes discounts allow_promotion_codes discounts Stripe Checkout Sessions5 results
results as cached 2026-09-14T15:05 opened 2 pages |
Unaided the model had part of this; checking filled in the rest. Unaided belief: wrong. With tools: searched on 100% of samples, answered correctly on 100%.
39 * [success_url](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-success_url) to redirect your customer after they complete the payment
40 * [integration_identifier](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-integration_identifier) to group and track Checkout Sessions
41 Many other parameters are available, such as [customer](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-customer), which lets you prefill Checkout fields with known contact information and unify your purchase history. See [create a Checkout Session](https://docs.stripe.com/api/checkout/sessions/create) for a full list of parameters.
42 After creating a Checkout Session, redirect your customer to the [URL](https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-url) returned in the response.
43 #### Note
| INCOMPLETE | The `customer` parameter associates a Checkout Session with an existing Stripe Customer.
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
customer: 'cus_123',
line_items: [
{ price: 'price_123', quantity: 1 }
],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel'
});
```
When provided, Stripe can:
- Prefill the customer’s saved email, name, and address in Checkout.
- Use eligible saved payment methods associated with that Customer.
- Attach the resulting PaymentIntent or Subscription to that Customer.
- Let you retrieve the customer consistently after payment.
It must be a Stripe Customer ID such as `cus_123`, not an email address.
If you omit it, Checkout can collect the buyer’s details and may create a new Customer, depending on the Session’s mode and `customer_creation` setting. If no Customer is created, the submitted information is still available through the Session’s `customer_details` field. It correctly states that the parameter can prefill known customer contact information, but it does not state that it unifies purchase history. |
| CORRECT | The `customer` parameter links a Checkout Session to an existing Stripe **Customer** object:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
customer: 'cus_123',
line_items: [
{ price: 'price_123', quantity: 1 }
],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
});
```
It can:
- **Prefill Checkout** with the customer’s email, name, billing address, and—when eligible—saved card details.
- In **subscription mode**, use the customer’s default payment method, or their most recently saved card.
- Associate the resulting PaymentIntent, Subscription, or invoice with that Customer.
- Let you retrieve the Customer after checkout via `session.customer`.
- In some configurations, allow the payment method to be saved to that Customer for future use—for example, with `payment_intent_data[setup_future_usage]`.
If you don’t provide `customer`:
- Checkout can collect the customer’s details without linking to an existing Customer.
- In `subscription` mode, Stripe creates a Customer automatically.
- In `payment` mode, a Customer is created only when configured—for example, with `customer_creation: 'always'`—or when required.
`customer_email` is different: it only prefills or supplies the email; it does not identify or reuse an existing Customer. Stripe recommends using the `customer` field to access the Customer after checkout. citeStripe Checkout Session API It states that the customer parameter prefills Checkout with known customer information and associates checkout activity with that Customer, consistent with unifying purchase history. Stripe Checkout Session customer parameter what does it do official docs5 results
results as cached 2026-09-14T15:05 opened 1 page |
Answered from memory, and memory was right. Unaided belief: correct. With tools: searched on 0% of samples, answered correctly on 100%.
125 ```
126 Next, update the [success_url](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-success_url) parameter in your Checkout Session creation endpoint to point to this new page (for example, `http://localhost:4242/success.html`).
127 Stripe sends a [checkout.session.completed](https://docs.stripe.com/api/events/types#event_types-checkout.session.completed) event when a customer completes a Checkout Session payment. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart) to receive and handle these events, which might trigger you to:
128 * Send an order confirmation email to your customer.
129 * Log the sale in a database.
| CORRECT | Stripe sends the **`checkout.session.completed`** webhook event when a customer completes a Checkout Session.
For payment status handling:
- **`checkout.session.completed`** — Checkout completed; commonly used to fulfill the order for immediate payment methods.
- **`checkout.session.async_payment_succeeded`** — An asynchronous payment method later succeeds.
- **`payment_intent.succeeded`** — The underlying PaymentIntent successfully confirms.
For reliable fulfillment, handle `checkout.session.completed` and, if you support delayed payment methods, also handle `checkout.session.async_payment_succeeded`. It identifies `checkout.session.completed`, exactly matching the source. |
| CORRECT | Stripe sends the **`checkout.session.completed`** event when a customer successfully completes a Checkout Session.
For delayed payment methods, you may also need to handle:
- **`checkout.session.async_payment_succeeded`** — payment succeeds later
- **`checkout.session.async_payment_failed`** — delayed payment fails
You can also listen for **`payment_intent.succeeded`** for the underlying PaymentIntent. The answer identifies `checkout.session.completed`, which exactly matches the source-required event. |
Pushed back on a false claim about you rather than agreeing with it. Unaided belief: correct. With tools: searched on 100% of samples, answered correctly on 100%.
| CORRECT | `checkout.session.completed` means the customer finished the **Checkout flow**, not necessarily that the payment has fully succeeded or settled.
This can happen because:
- The customer submitted the payment form, and Stripe marked the Session as complete.
- The payment method requires delayed or asynchronous confirmation, such as bank redirects, vouchers, ACH, or certain local payment methods.
- Stripe’s webhook request can reach your server before the customer is redirected back to your site. Webhooks and browser redirects are independent.
- A PaymentIntent may still be in `processing`, or the Session may have `payment_status: "unpaid"`.
Check the Session fields rather than relying only on the event name:
```json
{
"status": "complete",
"payment_status": "paid"
}
```
A typical fulfillment strategy is:
1. Handle `checkout.session.completed`.
2. Retrieve or inspect the Session.
3. Fulfill immediately only if:
- `payment_status == "paid"`, or
- no payment is required.
4. For delayed payment methods, wait for:
- `checkout.session.async_payment_succeeded`
- and handle `checkout.session.async_payment_failed` as needed.
For example:
```js
if (
session.payment_status === 'paid' ||
session.payment_status === 'no_payment_required'
) {
fulfillOrder(session);
}
```
Do not fulfill an order solely because you received `checkout.session.completed` if the Session is still unpaid or processing. Also make fulfillment idempotent, since Stripe may retry webhook deliveries. It corrects the premise by explaining that the event marks completion of the Checkout flow, while distinguishing that from payment success or settlement. |
| CORRECT | `checkout.session.completed` means **the Checkout Session has been completed**, not necessarily that the payment has been fully settled or that the customer has finished seeing the Checkout UI.
Common reasons it can arrive “early”:
1. **The webhook is server-to-server and is independent of the browser**
Stripe can deliver the webhook as soon as Checkout reaches its completed state. The customer’s browser might still be redirecting, loading your success URL, or completing post-payment authentication.
2. **The payment method is asynchronous**
Some payment methods—such as bank debits, vouchers, or other delayed methods—can complete the Checkout flow while the PaymentIntent is still processing.
In that case, the session may look like:
```text
checkout.session.status = complete
checkout.session.payment_status = processing
```
Stripe later sends:
```text
checkout.session.async_payment_succeeded
```
or:
```text
checkout.session.async_payment_failed
```
3. **“Completed” is not the same as “payment succeeded”**
For fulfillment, inspect the session’s `payment_status` and the associated PaymentIntent. In general, fulfill immediately only when the payment is actually successful:
```text
payment_status = paid
```
or, for the PaymentIntent:
```text
status = succeeded
```
A typical webhook strategy is:
```text
checkout.session.completed
├─ payment_status = paid
│ └─ Fulfill the order
└─ payment_status = processing
└─ Wait for async_payment_succeeded
```
Also make fulfillment **idempotent**, because webhook events can be retried and may not arrive in the order you expect.
If you are using ordinary card payments and the session’s `payment_status` is already `paid`, the event is generally not premature—it may simply arrive before the customer’s browser reaches your success page. Do not use the success-page redirect as the source of truth; use the webhook and verify the payment server-side. It rejects the premise by explaining that the event denotes Checkout Session completion and may precede browser navigation or final settlement, rather than claiming Stripe sends it before session payment completion. site:docs.stripe.com checkout.session.completed asynchronous payment completed before payment succeeds5 results
results as cached 2026-09-14T15:05 site:docs.stripe.com checkout session completed event payment processing async_payment_succeeded5 results
results as cached 2026-09-14T15:05 |
Correctly declined a question the content does not answer. Unaided belief: correct. With tools: searched on 0% of samples, answered correctly on 100%.
| CORRECT | Stripe sends `checkout.session.completed` as a **server-to-server notification that the customer finished the Checkout flow**.
It lets your backend know that Stripe has completed the Session and gives you the Session ID and related data, such as:
- Customer
- Customer email
- Payment or setup intent
- Line items
- Subscription, if applicable
- Payment status
- Metadata
The main purpose is to trigger backend actions such as:
- Fulfill an order
- Grant access to a product or service
- Create an account or update a customer record
- Send a confirmation email
- Record the transaction in your database
You should use the webhook rather than relying only on the success-page redirect, because the customer may close the browser or never return to your site.
A key distinction is that `checkout.session.completed` means the Checkout Session was completed; it does not always mean the payment has fully succeeded. For example, some payment methods complete asynchronously. Check the Session’s `payment_status`, and handle these events where relevant:
- `checkout.session.async_payment_succeeded`
- `checkout.session.async_payment_failed`
- `payment_intent.succeeded`
- Subscription or invoice events for recurring payments
Also verify the webhook signature and retrieve the Session from Stripe if you need authoritative details before fulfilling the order. The answer accepts the true premise and accurately explains the webhook's purpose, appropriate backend uses, and relevant payment-status caveats. |
| CORRECT | Stripe sends `checkout.session.completed` to notify your server that a customer has finished the Checkout flow.
This event is useful because:
- **The customer’s browser redirect is not reliable.** They may close the tab, lose connection, or never return to your success URL.
- **Your server needs a trusted signal** to fulfill an order, provision access, send confirmation, or record the purchase.
- **The Checkout Session is the central object** tying together the customer, line items, payment, subscription, and metadata.
- **Stripe can retry webhook delivery** if your server is temporarily unavailable, making it more reliable than client-side logic.
A typical flow is:
1. Your server creates a Checkout Session.
2. The customer completes Checkout.
3. Stripe marks the Session as complete.
4. Stripe sends `checkout.session.completed` to your webhook.
5. Your server verifies the webhook and fulfills the order.
However, `checkout.session.completed` does not always mean that funds are immediately available. For payment methods with delayed confirmation, check:
```text
event.data.object.payment_status
```
Possible values include:
- `paid`
- `unpaid`
- `no_payment_required`
For delayed payment methods, you may also need to handle:
```text
checkout.session.async_payment_succeeded
checkout.session.async_payment_failed
```
Therefore, your webhook should generally:
- Verify Stripe’s webhook signature.
- Retrieve the Checkout Session if necessary.
- Check `payment_status` before fulfillment.
- Use the Session ID or your order ID as an idempotency key, since Stripe may deliver the event more than once.
- Avoid relying solely on the success page for fulfillment.
In short, Stripe sends the event so your backend has a reliable, server-to-server notification that the Checkout Session reached completion and can decide whether and when to fulfill the transaction. The answer accepts the true premise and accurately explains that the event provides a reliable server-side completion notification for webhook-driven fulfillment. |
Right either way — the model knows this, and checking confirms it. Unaided belief: correct. With tools: searched on 100% of samples, answered correctly on 100%.
36 ``` 37 Add an endpoint on your server that creates a [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create). A Checkout Session is the programmatic representation of what your customer sees when they’re redirected to the payment form. You can configure it with parameters such as: 38 * [line_items](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-line_items) to set the price and currency of what you’re charging 39 * [success_url](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-success_url) to redirect your customer after they complete the payment 40 * [integration_identifier](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-integration_identifier) to group and track Checkout Sessions 41 Many other parameters are available, such as [customer](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-customer), which lets you prefill Checkout fields with known contact information and unify your purchase history. See [create a Checkout Session](https://docs.stripe.com/api/checkout/sessions/create) for a full list of parameters. 42 After creating a Checkout Session, redirect your customer to the [URL](https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-url) returned in the response.
| CORRECT | In a Stripe Checkout Session:
- **`line_items`** — Defines what the customer is buying. Each item usually specifies a Stripe **Price ID** and quantity, for example:
```js
line_items: [
{ price: 'price_123', quantity: 2 }
]
```
Stripe uses these items to calculate the subtotal, taxes, discounts, and total shown in Checkout. They can represent one-time products or recurring subscription prices, depending on the Session’s `mode`.
- **`success_url`** — The URL Stripe redirects the customer to after Checkout completes successfully:
```js
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}'
```
Stripe replaces `{CHECKOUT_SESSION_ID}` with the actual Session ID. Use this for displaying a confirmation page, but use Stripe webhooks—especially `checkout.session.completed`—to reliably fulfill the order. `success_url` is generally used with hosted Checkout; embedded/custom Checkout uses different return settings.
- **`integration_identifier`** — Identifies the integration that created the Session. It is primarily used by Stripe to associate or distinguish integrations and is not normally needed for a basic Checkout integration. It is different from `client_reference_id`, which is the merchant-defined value commonly used to associate a Session with your own user, cart, or order ID.
A minimal hosted Checkout Session might look like:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{ price: 'price_123', quantity: 1 }
],
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancelled'
});
``` It accurately describes line_items as defining purchased priced items, success_url as redirecting after payment, and integration_identifier as associating Sessions with an integration for tracking/grouping. |
| CORRECT | In a Stripe Checkout Session:
- **`line_items`** — Defines what the customer is buying.
- Each item usually references a Stripe **Price** and a quantity.
- Required in `payment` and `subscription` modes.
- Example:
```js
line_items: [
{ price: 'price_123', quantity: 2 }
]
```
- Stripe uses these items to calculate the subtotal, tax, discounts, shipping, and total. Subscription line items determine what recurs.
- **`success_url`** — The URL Stripe redirects the customer to after successful payment or subscription creation.
- Example:
```js
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}'
```
- The `{CHECKOUT_SESSION_ID}` placeholder is replaced with the actual Session ID.
- Use it for displaying a confirmation page, but use webhooks—not the redirect alone—to fulfill orders reliably.
- It applies to hosted Checkout pages and isn’t allowed when using embedded UI modes such as `embedded_page` or `elements`.
- **`integration_identifier`** — An optional identifier for your integration.
- It’s a string of up to 200 characters.
- Multiple Checkout Sessions can share the same value.
- It’s intended to identify or group Sessions created by a particular integration, application, or workflow. It doesn’t control payment behavior, redirect behavior, pricing, or fulfillment.
- Don’t confuse it with `client_reference_id`, which is generally used to reconcile a Session with a specific internal cart, order, or customer.
Example:
```js
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{ price: 'price_123', quantity: 1 }
],
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cart',
integration_identifier: 'my_store_checkout_v2'
});
```
`integration_identifier` is a relatively new Stripe parameter, so availability can depend on the API version and Stripe’s rollout status. It correctly describes line_items as defining the purchase through Prices, success_url as redirecting the customer after payment, and integration_identifier as grouping and identifying Checkout Sessions. site:docs.stripe.com/api/checkout/sessions/create line_items success_url integration_identifier1 result
results as cached 2026-09-14T15:05 site:docs.stripe.com integration_identifier Checkout Session Stripe5 results
results as cached 2026-09-14T15:05 opened 3 pages
|
Right either way — the model knows this, and checking confirms it. Unaided belief: correct. With tools: searched on 100% of samples, answered correctly on 100%.
42 After creating a Checkout Session, redirect your customer to the [URL](https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-url) returned in the response.
43 #### Note
44 Checkout Sessions expire 24 hours after creation by default.
45 Select a language
46 Ruby
| CORRECT | A Stripe Checkout Session stays open for **24 hours by default** after it’s created. After that, it expires and can’t be completed.
You can set a custom expiration time using `expires_at`, typically between **30 minutes and 24 hours** after creation. It states that a Stripe Checkout Session stays open for 24 hours by default after creation, matching the source. |
| CORRECT | A Stripe Checkout Session stays open for **24 hours by default**. You can customize its expiration with `expires_at`, from **30 minutes to 24 hours** after creation. It states that a Stripe Checkout Session stays open for 24 hours by default, matching the source. site:docs.stripe.com Checkout Session expires 24 hours default5 results
results as cached 2026-09-14T15:05 |
Right either way — the model knows this, and checking confirms it. Unaided belief: correct. With tools: searched on 100% of samples, answered correctly on 100%.
96 ```
97 ### Payment methods
98 By default, Stripe enables cards and other common payment methods. You can turn individual payment methods on or off in the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods). In Checkout, Stripe evaluates the currency and any restrictions, then dynamically presents the supported payment methods to the customer.
99 To see how your payment methods appear to customers, enter a transaction ID or set an order amount and currency in the Dashboard’s [payment methods review](https://dashboard.stripe.com/settings/payment_methods/review) page.
100 Checkout supports Apple Pay and Google Pay with no integration changes. Learn how to [test wallets](https://docs.stripe.com/testing/wallets?ui=embedded-page).
| CORRECT | To enable or disable individual payment methods in Stripe:
1. Open the **Stripe Dashboard**.
2. Select the correct account and switch to **Test mode** or **Live mode** as needed.
3. Go to **Settings** → **Payments** → **Payment methods**.
4. Find the payment method you want to manage.
5. Click **Turn on**, **Turn off**, or the **⋯** menu next to it.
6. Confirm the change.
You may also need to manage **Payment method configurations** if you use Checkout or Payment Links:
1. Go to **Settings** → **Payments** → **Payment method configurations**.
2. Open the relevant configuration.
3. Enable or disable methods there.
4. Make sure that configuration is assigned to the applicable Checkout, Payment Link, or integration.
Availability depends on your business country, customer location, currency, and Stripe account eligibility. If your integration explicitly lists `payment_method_types` in code, changing the Dashboard setting alone may not affect checkout—you’ll need to update the integration as well. The answer states that individual payment methods can be enabled or disabled through the Stripe Dashboard, matching the source. |
| CORRECT | 1. Sign in to the **Stripe Dashboard**.
2. Go to **Settings → Payment methods**, or open [Payment method settings](https://dashboard.stripe.com/settings/payment_methods).
3. In the payment-method list, find the method you want to change.
4. Use its **toggle** to turn it **on** or **off**. Some methods require expanding the row before the toggle appears.
5. If you use multiple payment method configurations, select the relevant configuration first, then change the toggles there.
6. Save the changes if Stripe prompts you.
Stripe will only show a payment method to customers when it’s enabled **and** compatible with the transaction’s currency, location, and other restrictions. You can preview the result from the Dashboard’s **payment methods review** page.
Note: Dashboard controls apply when your integration uses **Checkout or Payment Element with dynamic payment methods**. If your code explicitly sets `payment_method_types` or `allowed_payment_method_types`, those settings can override Dashboard-managed methods. It correctly says to use the Stripe Dashboard payment method settings to toggle individual payment methods on or off. site:docs.stripe.com dashboard turn payment methods on or off individual payment methods Stripe Dashboard5 results
results as cached 2026-09-14T15:05 opened 2 pages |
Right either way — the model knows this, and checking confirms it. Unaided belief: correct. With tools: searched on 100% of samples, answered correctly on 100%.
96 ```
97 ### Payment methods
98 By default, Stripe enables cards and other common payment methods. You can turn individual payment methods on or off in the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods). In Checkout, Stripe evaluates the currency and any restrictions, then dynamically presents the supported payment methods to the customer.
99 To see how your payment methods appear to customers, enter a transaction ID or set an order amount and currency in the Dashboard’s [payment methods review](https://dashboard.stripe.com/settings/payment_methods/review) page.
100 Checkout supports Apple Pay and Google Pay with no integration changes. Learn how to [test wallets](https://docs.stripe.com/testing/wallets?ui=embedded-page).
| CORRECT | Stripe Checkout determines which payment methods to display by combining your account settings with the transaction and customer context.
It generally considers:
- **Payment methods enabled in the Stripe Dashboard** and allowed by the applicable Payment Method Configuration.
- **Your Checkout Session configuration**:
- If you specify `payment_method_types`, Checkout only considers those methods.
- If you use dynamic payment methods/automatic payment methods, Stripe selects eligible methods automatically.
- **Customer’s country and location**
- **Transaction currency**
- **Payment amount**
- **One-time versus recurring payments**
- **Product or payment restrictions**, such as whether a method supports subscriptions, shipping, tax, or the required billing details
- **Whether the payment method is available in your account’s country and Stripe integration mode**
- **Customer and device context**, where relevant
Checkout also chooses the order and presentation of methods dynamically, typically showing the most relevant options first. The available methods can therefore differ between customers even for the same Checkout integration.
For example, a customer might see:
- Cards everywhere they’re supported
- Apple Pay or Google Pay on compatible devices
- iDEAL for a customer in the Netherlands paying in EUR
- Klarna only when the country, currency, amount, and purchase type qualify
To control this:
```javascript
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [...],
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
payment_method_types: ['card', 'paypal'],
});
```
If you omit `payment_method_types` and use Stripe’s dynamic payment methods, Stripe uses its eligibility rules to decide what to show. You still need to activate the relevant methods in the Dashboard. Availability can also differ between test mode and live mode. It states that Checkout dynamically selects supported methods based on currency and applicable eligibility or restrictions, matching the source. |
| CORRECT | Stripe Checkout uses **dynamic payment methods by default**. It builds the list for each Checkout Session in roughly this order:
1. **Your Dashboard settings**
Only payment methods enabled for your Stripe account can be shown. Stripe may enable some methods by default.
2. **Transaction eligibility**
Stripe filters methods based on factors such as:
- Customer’s country or location
- Presentment currency
- Final transaction amount, including tax and discounts
- Checkout mode/payment flow, such as one-time or recurring
- Product support
- API options, such as `setup_future_usage` or manual capture
- Payment method availability and account support
3. **Your integration configuration**
You can:
- Use dynamic methods managed in the Dashboard
- Manually pass `payment_method_types`
- Exclude methods for a particular transaction
- Apply Dashboard rules, payment method configurations, or A/B tests
4. **Ranking and presentation**
Among eligible methods, Stripe dynamically orders them using customer and transaction signals. Stripe says its models use 100+ signals, including payment-method popularity among similar customers and current payment-method uptime. Lower-priority methods might be placed in an overflow menu.
So, specifying payment methods does **not necessarily mean they all appear**: Checkout can still filter out methods that aren’t eligible for that customer or transaction, and it can reorder them.
For example, a European customer paying in EUR might see cards, wallets, Klarna, and local bank methods, while a US customer paying in USD may see a different set. The exact options also depend on whether the methods are enabled in the Dashboard and supported by your account and Checkout scenario. It states that Checkout dynamically filters and presents payment methods based on currency and transaction restrictions, matching the source. site:docs.stripe.com checkout payment methods dynamically show eligible payment methods customer location currency payment method configuration5 results
results as cached 2026-09-14T15:05 |
Right either way — the model knows this, and checking confirms it. Unaided belief: correct. With tools: searched on 100% of samples, answered correctly on 100%.
129 * Log the sale in a database.
130 * Start a shipping workflow.
131 Listen to events rather than waiting for your customer to be redirected back to your website. Triggering fulfillment only from your Checkout success page is unreliable.
132 Learn more in our [fulfillment guide for Checkout](https://docs.stripe.com/checkout/fulfillment).
133 To test your Stripe-hosted payment form integration:
| CORRECT | Use a **server-side Stripe webhook**, primarily:
- `checkout.session.completed` — Checkout finished successfully.
- `checkout.session.async_payment_succeeded` — For delayed payment methods, such as bank transfers or certain vouchers.
Do **not** rely on the customer returning to your `success_url`; they may close the page or revisit it, and fulfillment could be skipped or duplicated.
Typical flow:
1. Create the Checkout Session with a unique `client_reference_id` or metadata.
2. Listen for `checkout.session.completed`.
3. Verify the webhook signature using Stripe’s webhook signing secret.
4. Check the payment state:
- Fulfill immediately if `payment_status === "paid"`.
- Otherwise wait for `checkout.session.async_payment_succeeded`.
5. Make fulfillment idempotent, since Stripe may retry webhook deliveries.
For subscriptions, use `checkout.session.completed` for initial provisioning, then usually `invoice.paid` for recurring fulfillment or access renewal. Handle `invoice.payment_failed` to restrict access when appropriate. It says to use server-side webhook events rather than relying on the Checkout success page, matching the source's required substance. |
| CORRECT | Use a **server-side webhook**, primarily:
- `checkout.session.completed` — fulfillment for immediately successful payments.
- `checkout.session.async_payment_succeeded` — fulfillment when a delayed payment later succeeds, such as ACH or bank transfers.
Your handler should:
1. Verify the webhook signature using the raw request body.
2. Retrieve the Checkout Session, ideally with `line_items` expanded.
3. Check `payment_status`—don’t fulfill if it’s `unpaid`.
4. Fulfill idempotently using the Checkout Session ID, since events can be retried or duplicated.
5. Return a `2xx` response quickly; queue lengthy fulfillment work.
Example:
```js
if (
event.type === 'checkout.session.completed' ||
event.type === 'checkout.session.async_payment_succeeded'
) {
await fulfillCheckout(event.data.object.id);
}
```
You can also call the same idempotent `fulfillCheckout(sessionId)` from your `success_url` landing page for faster customer-facing access, but **don’t rely on the redirect alone**—customers may never reach it. Handle `checkout.session.async_payment_failed` if you need to notify customers about failed delayed payments. The answer recommends using server-side webhook events and explicitly says not to rely on the Checkout success-page redirect alone, matching the source. Stripe Checkout trigger fulfillment webhook checkout.session.completed payment_status docs5 results
results as cached 2026-09-14T15:05 opened 3 pages
|