payloadcms/payload · error · Error
PaymentIntent ID is required
Error message
PaymentIntent ID is required
What it means
Thrown by Stripe confirmOrder when data.paymentIntentID is falsy. confirmOrder needs the PaymentIntent ID (returned by initiatePayment) to look up the transaction and retrieve the intent from Stripe. Without it the adapter cannot correlate the order with a payment. This is an input-contract violation: the caller omitted the paymentIntentID field on the confirmOrder request body.
Source
Thrown at packages/plugin-ecommerce/src/payments/adapters/stripe/confirmOrder.ts:33
cartsSlug = 'carts',
data,
ordersSlug = 'orders',
req,
transactionsSlug = 'transactions',
}) => {
const payload = req.payload
const { apiVersion, appInfo, secretKey } = props || {}
const customerEmail = data.customerEmail
const paymentIntentID = data.paymentIntentID as string
if (!secretKey) {
throw new Error('Stripe secret key is required')
}
if (!paymentIntentID) {
throw new Error('PaymentIntent ID is required')
}
const stripe = new Stripe(secretKey, {
// API version can only be the latest, stripe recommends ts ignoring it
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - ignoring since possible versions are not type safe, only the latest version is recognised
apiVersion: apiVersion || '2025-03-31.basil',
appInfo: appInfo || {
name: 'Stripe Payload Plugin',
url: 'https://payloadcms.com',
},
})
try {
let customer = (
await stripe.customers.list({
email: customerEmail,
})View on GitHub (pinned to 00c58b35c0)
Solutions
- Capture the paymentIntentID returned by initiatePayment and send it in the confirmOrder request body as paymentIntentID.
- Validate the field client-side before calling confirm (non-empty string).
- Store the paymentIntentID in a durable client store (sessionStorage / cookie) across the redirect flow.
- If using a webhook, ensure the webhook reads the intent id from the Stripe event and forwards it.
Example fix
// before: confirm call missing the id
await payments.confirmOrder({ data: {} })
// after: thread the id from initiatePayment
const { paymentIntentID } = await payments.initiatePayment({ data })
await payments.confirmOrder({ data: { paymentIntentID } }) Defensive patterns
Strategy: validation
Validate before calling
export function assertPaymentIntentID(value: unknown): asserts value is string {
if (typeof value !== 'string' || value.trim().length === 0) {
throw new Error('paymentIntentID is required and must be a non-empty string')
}
}
// before confirmOrder
assertPaymentIntentID(data.paymentIntentID)
await payments.confirmOrder({ data }) Type guard
export function isPaymentIntentID(value: unknown): value is string {
return typeof value === 'string' && value.startsWith('pi_')
} Try / catch
try {
await payments.confirmOrder({ data: { paymentIntentID } })
} catch (err) {
if (err instanceof Error && err.message === 'PaymentIntent ID is required') {
// client lost the id — re-initiate or surface a clear checkout error
return { ok: false, reason: 'missing-payment-intent', redirect: '/checkout' }
}
throw err
} Prevention
- Persist paymentIntentID in sessionStorage/cookie across the Stripe redirect flow.
- Validate the id client-side (starts with 'pi_', non-empty) before calling confirm.
- Name the field exactly paymentIntentID (Stripe uses pi_ IDs; your contract uses paymentIntentID).
- In integration tests, always chain initiate -> confirm to avoid orphan confirm calls.
When it happens
Trigger: A client calls the confirm-order endpoint without passing the paymentIntentID it received from initiatePayment, or passes it as an empty string/null. Also occurs if a frontend wires the confirm step to the wrong state variable.
Common situations: Frontend checkout flow loses the paymentIntentID between steps (page reload, state reset); a webhook handler calling confirmOrder without the ID; integration tests that skip the initiate step; misnamed fields (payment_intent_id vs paymentIntentID).
Related errors
- Currency is required.
- Cart is empty or not provided.
- A valid customer email is required to make a purchase.
- Payment not completed.
- Cart items snapshot not found or invalid in the PaymentInten
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/65b4edc893d2b8cd.
Report an issue: GitHub.