Skip to documentation content

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.

FlowUse it whenCarden key scopes
Linked invoice sourceThe payment maps to one imported, fully unpaid invoice.invoices:read + enrichment:write; the report worker also needs payments:write.
Inline invoiceThe backend already has a complete CanonicalInvoice v1.enrichment:write; add payments:write when the same service reports.
Reporting onlyThe service only records payment outcomes.payments:write.

Set up the linked source

  1. Connect a supported invoice source for the merchant and complete the initial invoice import.
  2. Review source exceptions and approve only factual product-code or unit mappings.
  3. Link the invoice source to Stripe inside the same merchant and environment with authority over both integrations.
  4. 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.

  1. Find

    Use an invoice reference

    Supply the known Carden invoice ID for the payment.

  2. Prepare

    Create Stripe fields

    Carden validates amount, currency, current source state, and eligibility.

  3. Save

    Store the preparation

    Attach immutable preparation evidence and the diagnostic request ID to the attempt.

  4. Pay

    Execute Stripe once

    The backend merges enrichment and uses its own Stripe idempotency key.

  5. Queue

    Persist the observation

    A durable worker sends the saved report independently of checkout.

Server-side linked payment
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

IdentifierPurpose
Preparation idempotencyKeyReuses an identical preparation request while current source checks still pass.
preparation.idStable source-backed preparation identity used as the report enrichmentRequestId.
x-carden-request-idIdentifies one Carden HTTP request for diagnostics.
Stripe idempotency keyProtects one merchant-owned Stripe payment operation.
attemptId / eventIdIdentify 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.