Skip to content

Stripe order identity and duplicate prevention

Use one durable merchant-owned purchase request, order, pending entitlement, or equivalent record for one intended purchase. Create or recover that row before calling Proxy, derive the Proxy session-create idempotency key from its stable non-PII ID, persist the returned Proxy session ID, and share the same handoff URL with every authorized payer.

Value Question answered Example
Stable session-create idempotency key Which intended purchase/order should reuse one Proxy session? proxy-session:purchase_request_123
buyerReference Who receives the merchant-owned benefit? pending_entitlement_456

They may contain the same pending-entitlement ID in a simple data model, but they are separate concepts. Do not invent a new Proxy cross-session identity subsystem.

const purchaseRequest = await findOrCreatePurchaseRequest({
clientRequestId,
offerId,
beneficiaryId,
});
const handoff = await proxy.sessions.createHandoff({
amountMinor: purchaseRequest.amountMinor,
buyerReference: purchaseRequest.beneficiaryId,
cartSnapshot: purchaseRequest.cartSnapshot,
currency: purchaseRequest.currency,
idempotencyKey: `proxy-session:${purchaseRequest.id}`,
});
await purchaseRequest.attachProxySession({
handoffUrl: handoff.handoffUrl,
proxySessionId: handoff.id,
});

Retries must reuse the purchase-request row and reject attempts to change its beneficiary, offer, or immutable identity. A genuinely new purchase gets a new purchase-request ID even when the beneficiary, amount, and offer are identical.

Share one stored handoff URL when a buyer invites two parents or other payers. Do not create a Proxy session per payer, browser, device, message, or link open. Both payers can render and interact with the same current Stripe root concurrently. Neither opening becomes the owner; neither waits for the other to leave or for an expiry timer.

When one qualifying payment completes, every page keeps the cart visible and renders an explicit completed state. The backend returns already_paid and performs zero new Stripe object creation. If an out-of-band second success exists despite the normal helper path, Proxy retains it as a financial fact and fee but refuses a second provisioning winner.

Do not use any of these as the purchase-request identity:

  • email, phone, or other PII;
  • payer identity or browser/session identity;
  • Stripe Customer, PaymentMethod, PaymentIntent, or Checkout Session ID;
  • amount or cart total alone;
  • buyerReference alone without a durable purchase-attempt policy;
  • a random UUID regenerated on every retry.

The Proxy session ID is public correlation, not a claim secret. For pre-account access, keep the beneficiary claim token merchant-owned, store only its hash, and never put it in Proxy/Stripe metadata or the cart snapshot.