Shadow Stripe flow
Run the provider-specific payment rehearsal from CI and launch automation.
Shadow Stripe flow
Shadow mode is the Stripe-specific automation path for validating a real test-mode Checkout session and proving the expected database side effect occurred. It lives outside API v1 because the workflow is provider-specific and interactive.
Endpoints
paid and polls Supabase for the mapped side effect.
Authentication uses the same bearer API keys as API v1 (Authorization: Bearer pf_live_…).
Request and response
Start
POST /api/projects/:projectId/shadow/start
Authorization: Bearer pf_live_...
Content-Type: application/json
Idempotency-Key: ci-preview-123
{
"previewUrl": "https://preview.example.com",
"priceKey": "pro-monthly",
"source": "github_action"
}
| Field | Required | Description |
|---|---|---|
previewUrl |
No | Base URL for success/cancel redirects when not set on integration |
priceKey |
No | Stable key from testPrices; omit for the first/default configured plan |
source |
No | api or github_action — stored on the check run for audit |
Response:
{
"runId": "uuid",
"status": "running",
"traceId": "pf_trace_…",
"checkoutSessionId": "cs_test_…",
"checkoutUrl": "https://checkout.stripe.com/c/pay/…",
"priceKey": "pro-monthly",
"priceLabel": "Pro monthly",
"priceId": "price_…",
"checkoutMode": "subscription"
}
Finalize
POST /api/projects/:projectId/shadow/finalize
Authorization: Bearer pf_live_...
Content-Type: application/json
{
"runId": "uuid",
"traceId": "pf_trace_…",
"checkoutSessionId": "cs_test_…"
}
Response on success:
{
"runId": "uuid",
"traceId": "pf_trace_…",
"status": "success",
"stage": "supabase_side_effect",
"message": "Shadow checkout verified end to end."
}
Failed responses include stage (stripe_payment or supabase_side_effect) and probe-level details for triage.
When to use it
Required Stripe integration fields
Configure these on the project's Stripe integration before starting a shadow run:
PreFlight can scan the connected Supabase OpenAPI schema and suggest the strongest mapping. If the saved mapping misses during a run, verification also attempts discovered trace-bearing tables before failing.
Optional verification fields
Trace ID propagation
PreFlight generates a pf_trace_… ID and embeds it in:
- Checkout session
metadata.preflight_trace_id client_reference_id- Payment intent metadata for one-time plans, or
subscription_data.metadatafor recurring plans
For recurring plans, this verifies the initial paid Checkout and the existing trace-based Supabase fulfillment only. Renewal, cancellation, dunning, refunds, trials, coupons, and taxes are not part of this path.
Your webhook handler should persist the same trace value to verifyTraceColumn so finalize and Payment Sync can find the row.
Idempotency
Send an Idempotency-Key header on shadow/start from CI. If the deploy job retries, PreFlight returns the existing shadow run and Checkout URL instead of creating a second session.
Daily start limits apply per project (SHADOW_START_LIMIT_PER_DAY). Use idempotency to avoid exhausting the budget on flaky pipelines.
Autonomous batches, quota, and queueing
Revenue Guard runs each configured testPrices entry sequentially because the current database guard allows one active shadow child per project. Every price execution consumes one unit from the shared journey_run synthetic meter, using a stable price-specific idempotency key. The hosted Checkout runner uses the global browser semaphore shared with Journey Canary, so revenue checks queue behind the same capacity limit instead of creating a second unbounded browser pool. One failed plan does not stop the remaining plans.
Rate limits
sk_test_. Live keys cannot be used for synthetic Checkout sessions.
Probe timeline
Each shadow run writes deterministic probe rows:
Inspect these in Checks → run timeline or via GET /api/v1/projects/:id/checks/:runId.
<RelatedLinks links={[ { href: "/docs/guides/verify-stripe-checkout-without-a-real-credit-card", title: "Verify Checkout without a card", description: "Step-by-step dashboard and test card workflow." }, { href: "/docs/guides/revenue-watch", title: "Payment Sync", description: "Production reconciliation using the same mapping." }, { href: "/docs/integrations/stripe", title: "Stripe integration", description: "Webhook and verify field setup." }, { href: "/docs/api/authentication", title: "API authentication", description: "Bearer keys and idempotency headers." }, ]} />
