Getting started with Stripe
Prepare a Stripe payment from one authoritative source invoice and report the outcome from saved evidence.
On this page
Choose the linked flow deliberately
Carden reads an imported invoice from a supported source and returns fields for the merchant's existing Stripe PaymentIntent request. The Carden preparation request uses an invoice reference; the merchant backend does not resend the invoice line items. The merchant backend executes the payment with its own Stripe credentials and later sends Carden normalized observations.
| Flow | Use it when | Carden key scopes |
|---|---|---|
| Linked invoice source | The payment maps to one imported, fully unpaid invoice. | invoices:read + enrichment:write; the report worker also needs payments:write. |
| Inline invoice | The backend already has a complete CanonicalInvoice v1. | enrichment:write; add payments:write when the same service reports. |
| Reporting only | The service only records payment outcomes. | payments:write. |
Set up the linked source
- Connect a supported invoice source for the merchant and complete the initial invoice import.
- Review source exceptions and approve only factual product-code or unit mappings.
- Link the invoice source to Stripe inside the same merchant and environment with authority over both integrations.
- Create a Stripe-integration Carden key with invoices:read and enrichment:write; give the report worker payments:write.
Linking does not change existing keys. Create or rotate a key when a service needs invoice access, then keep it in server-only secret configuration.
Use one ready, fully unpaid invoice
Pass the known Carden invoice ID directly to preparation. Look up an invoice first only when you need to find its Carden ID or review readiness and issues. Carden rechecks source freshness and eligibility and returns the prepared line items. expectedRevision is an optional guard when you want to reject changes since a revision you reviewed.
- The invoice must be open, positive, fully unpaid, and unambiguous.
- The PaymentIntent amount and currency must match the invoice total and balance.
- The source must be active, current, and free of pending refresh work.
- Partial payments, combined invoices, overpayments, and ambiguous allocations require another supported workflow.
Prepare, pay, and queue the report
The example assumes order and attempt are saved application records. order.invoiceId is the known Carden invoice ID; order.invoiceNumber is an optional factual reference already stored with the order. attemptStore, executeStripePayment, and reportOutbox belong to the merchant backend. The Stripe operation returns an expanded latest_charge so the observation uses actual captured and refunded totals.
The linked payment flow
Save each identifier before the operation that depends on it.
Find
Use an invoice reference
Supply the known Carden invoice ID for the payment.
Prepare
Create Stripe fields
Carden validates amount, currency, current source state, and eligibility.
Save
Store the preparation
Attach immutable preparation evidence and the diagnostic request ID to the attempt.
Pay
Execute Stripe once
The backend merges enrichment and uses its own Stripe idempotency key.
Queue
Persist the observation
A durable worker sends the saved report independently of checkout.
import { paymentObservationFromStripePaymentIntent } from "@carden/node";
const { enrichment, preparation, requestId } =
await carden.stripe.createPaymentIntentEnrichmentFromInvoice({
invoiceId: order.invoiceId,
amountMinor: order.amountMinor,
currency: order.currency,
idempotencyKey: attempt.preparationIdempotencyKey,
});
await attemptStore.attachPreparation(attempt.attemptId, { preparation, requestId });
const result = await executeStripePayment({
amount: preparation.amountMinor,
currency: preparation.currency,
...enrichment,
}, { idempotencyKey: attempt.stripeIdempotencyKey });
await reportOutbox.enqueue({
eventId: attempt.eventId,
attemptId: attempt.attemptId,
occurredAt: new Date().toISOString(),
source: "api",
enrichmentRequestId: preparation.id,
...(order.invoiceNumber ? { invoiceReference: order.invoiceNumber } : {}),
...paymentObservationFromStripePaymentIntent(result),
});The outbox worker calls carden.stripe.reportPayment(report, { maxRetries: 0 }), keeps the same eventId across delivery retries, and treats duplicate: true as acknowledgment.
Keep identities separate
| Identifier | Purpose |
|---|---|
| Preparation idempotencyKey | Reuses an identical preparation request while current source checks still pass. |
| preparation.id | Stable source-backed preparation identity used as the report enrichmentRequestId. |
| x-carden-request-id | Identifies one Carden HTTP request for diagnostics. |
| Stripe idempotency key | Protects one merchant-owned Stripe payment operation. |
| attemptId / eventId | Identify one payment attempt and one immutable observation. |
A preparation retry can have a new HTTP request ID while retaining preparation.id. Changed invoice, amount, currency, source revision, or payment intent requires reviewed new work rather than reuse of an old identity.
Report later outcomes from saved evidence
Captures, refunds, cancellations, and later verified Stripe events reuse the original attemptId and preparation.id, while every new observation has a new eventId. Verify Stripe webhook signatures in the merchant backend and report cumulative amounts.
Use the saved preparation even if the source invoice changes or its integration disconnects after payment. A report amount or currency difference remains an actual payment observation and creates a correlation mismatch exception; Carden never rewrites it to fit the invoice.