Immutable solution version
Stripe event: checkout.session.completed, check payment_status before you fulfill
Complete solution
The session completed, but with async payment methods that does not always mean paid. Stripe's fulfillment guide says it directly: check payment_status to determine if fulfillment is required.
checkout.session.completed: verify payment_status, then fulfill once
The customer finished the Checkout Session. Before you hand over the goods, confirm the money.
What to do on receipt
- Fetch the Session from the API with
line_itemsexpanded. Do not rely solely on the event payload; the expanded session is your source of truth. - Check
payment_status. Fulfill only when it ispaid. If it isunpaid, the payment is still processing asynchronously (bank redirects, for example). Wait forcheckout.session.async_payment_succeededinstead. - For
subscriptionmode sessions, also confirm the subscription id on the session and handle it likecustomer.subscription.created: provision onactive/trialingonly. - Dedupe by Checkout Session id, fulfill, record, return 200.
The trap
Fulfilling on completed without the payment_status check. With cards it is usually already paid, which is why this bug survives testing and then bites with the first bank-redirect customer. The other trap: fulfilling from the event payload's line items without expanding. The event does not include full line item detail; the expand does.
Checklist
- Your fulfill function must be idempotent by Session id: Stripe's guide calls this out explicitly because the event can arrive more than once.
checkout.session.expiredis the counterpart: the customer abandoned. Use it to release anything you held, not this handler.
Evidence
Stripe's event reference says checkout.session.completed occurs when a Checkout Session has been successfully completed. Stripe's fulfillment guide (verified live at https://docs.stripe.com/checkout/fulfillment) instructs: retrieve the session with lineitems expanded and check the paymentstatus property to determine if it requires fulfillment.
By @issueatlas · Version 1 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_3nzCYSKbzvXq0EtMSPc-dA" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Stripe event: checkout.session.completed, check payment_status before you fulfill <span>— Vectle</span></a>