payloadcms/payload · error · Error
No transaction found for the provided PaymentIntent ID
Error message
No transaction found for the provided PaymentIntent ID
What it means
Thrown by Stripe confirmOrder after querying the transactions collection by stripe.paymentIntentID — if no transaction document is found (totalDocs === 0 or no doc returned), the PaymentIntent ID is unknown to the system. This means initiatePayment never persisted a transaction for that intent, or the transactions slug/name differs. It separates 'Stripe knows this intent' from 'the local system recorded it'.
Source
Thrown at packages/plugin-ecommerce/src/payments/adapters/stripe/confirmOrder.ts:74
email: customerEmail,
})
}
// Find our existing transaction by the payment intent ID
const transactionsResults = await payload.find({
collection: transactionsSlug,
req,
where: {
'stripe.paymentIntentID': {
equals: paymentIntentID,
},
},
})
const transaction = transactionsResults.docs[0]
if (!transactionsResults.totalDocs || !transaction) {
throw new Error('No transaction found for the provided PaymentIntent ID')
}
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentID)
if (paymentIntent.status !== 'succeeded') {
throw new Error(`Payment not completed.`)
}
const cartID = paymentIntent.metadata.cartID
const cartItemsSnapshot = paymentIntent.metadata.cartItemsSnapshot
? JSON.parse(paymentIntent.metadata.cartItemsSnapshot)
: undefined
const shippingAddress = paymentIntent.metadata.shippingAddress
? JSON.parse(paymentIntent.metadata.shippingAddress)
: undefined
if (!cartID) {View on GitHub (pinned to 00c58b35c0)
Solutions
- Ensure initiatePayment ran to completion for this paymentIntentID and a transaction document exists in the transactions collection.
- Confirm the transactionsSlug is identical for both initiatePayment and confirmOrder (default 'transactions').
- Inspect the transactions collection for stripe.paymentIntentID === <id> to verify persistence.
- If the intent was created outside the plugin, recreate it via initiatePayment so a transaction is recorded.
Example fix
// before: confirm an intent created outside the plugin
await payments.confirmOrder({ data: { paymentIntentID: externalIntentId } })
// after: always go through initiatePayment first so a transaction row exists
const { paymentIntentID } = await payments.initiatePayment({ data: cartData })
// ...user pays with Stripe checkout...
await payments.confirmOrder({ data: { paymentIntentID } }) Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: confirm a transaction exists for this intent before calling confirmOrder
async function transactionExistsForIntent(payload, transactionsSlug: string, paymentIntentID: string): Promise<boolean> {
const res = await payload.find({
collection: transactionsSlug,
where: { 'stripe.paymentIntentID': { equals: paymentIntentID } },
limit: 1,
})
return res.totalDocs > 0
}
if (!(await transactionExistsForIntent(payload, 'transactions', id))) {
throw new Error('No local transaction; run initiatePayment first')
} Type guard
export function hasLocalTransaction(res: { totalDocs: number; docs: unknown[] }): boolean {
return res.totalDocs > 0 && res.docs.length > 0
} Try / catch
try {
await payments.confirmOrder({ data: { paymentIntentID } })
} catch (err) {
if (err instanceof Error && err.message === 'No transaction found for the provided PaymentIntent ID') {
// intent is foreign or initiate didn't persist — re-run initiate or surface to support
return { ok: false, reason: 'orphan-intent' }
}
throw err
} Prevention
- Always create intents via initiatePayment so a transaction row is written.
- Use identical transactionsSlug on both initiate and confirm (default 'transactions').
- Idempotency-check the transactions collection before allowing confirm to run twice.
- In multi-environment setups, ensure initiate and confirm target the same database.
When it happens
Trigger: confirmOrder is called with a paymentIntentID that was never created via this plugin's initiatePayment (e.g. an intent created directly in the Stripe dashboard or a different integration), or the transaction was deleted, or transactionsSlug passed to confirmOrder differs from the one used in initiatePayment.
Common situations: Mixing Stripe dashboards / accounts between initiate and confirm; running confirm against a test intent from the Stripe UI; the transactions collection slug was customized on one side but not the other; database reset between the two steps; race condition where confirm runs before initiate's transaction create commits.
Related errors
- Cart ID not found in the PaymentIntent metadata
- Stripe secret key is required
- PaymentIntent ID is required
- 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/2adf0b876be4073f.
Report an issue: GitHub.