Files
member-console/docs/stripe.md
T

5.1 KiB

title, audience, summary
title audience summary
Stripe Integration
admin
developer
Configure Stripe: flags and file-based secrets, the webhook endpoint and events, catalog-to-Stripe sync, and making a product purchasable.

Stripe

This guide covers connecting the member console to Stripe for payment processing. The member console is the source of truth for the product catalog — Stripe handles payment execution.

Prerequisites

  • A Stripe account (test mode is fine for initial setup)
  • The Stripe secret key (sk_test_... or sk_live_...)
  • A webhook endpoint signing secret (whsec_...)

Configuration

Flag Description
--stripe-api-key Stripe secret key
--stripe-api-key-file Path to file containing the API key
--stripe-webhook-secret Webhook endpoint signing secret
--stripe-webhook-secret-file Path to file containing the webhook secret
--stripe-mode test or live (controls dashboard link URLs)

All flags support _FILE variants for secret injection from mounted files.

Webhook endpoint

Register a webhook in the Stripe Dashboard pointing to:

https://<your-domain>/webhooks/stripe

Subscribe to these event types:

  • customer.created, customer.updated, customer.deleted
  • product.created, product.updated, product.deleted
  • price.created, price.updated
  • checkout.session.completed, checkout.session.expired
  • customer.subscription.created, customer.subscription.updated, customer.subscription.deleted
  • invoice.created, invoice.finalized, invoice.paid, invoice.payment_failed, invoice.voided
  • payment_method.attached, payment_method.detached

How it works

The member console is the catalog source of truth; Stripe holds a mirror used for payment execution. Catalog objects do not sync to Stripe automatically — syncing a product to Stripe is an explicit operator action (see "Making a product purchasable" below). Once synced, members subscribe via Stripe Checkout, Stripe runs the billing cycle, and webhooks project Stripe state (subscriptions, invoices, payments) back into the member console's core tables.

Sync runs through a transactional outbox: the operator action enqueues create_stripe_product and create_stripe_price entries, and a worker drains them against the Stripe API. The resulting stripe.product_mappings / stripe.price_mappings rows record the mapping and its sync_status, which moves from pending to synced (or to deleted). dead_letter is a status on the outbox entry itself, not on the mapping: when an entry fails repeatedly and the outbox marks it dead_letter, the mapping it was trying to create stays at pending until an operator retries the entry and the retry succeeds.

Making a product purchasable

A member can only buy a product once every purchasability precondition is met. The operator product edit page (/operator/products/{id}) shows a Purchasability panel that evaluates each one and renders a single verdict — Purchasable or Incomplete — naming exactly what is missing. The preconditions:

  1. Published — set the product's lifecycle to published.
  2. Public & active — mark it Active and Public so it appears in the member catalog.
  3. Structural kind — put it on a plan ladder to sell it as a plan (a single-tier ladder is the idiom for a standalone plan), or give it a product type (addon / usage / one_time). A published, untyped product on no ladder is invisible "limbo", which the panel flags.
  4. Active price — add a price on the product's Prices view.
  5. Stripe-mapped price — the active price is mapped to a live Stripe price.

The last step is the one to do explicitly: on the Purchasability panel, click Sync to Stripe. That enqueues the product and price sync; the precondition shows Sync pending until the outbox worker drains, then flips to Met and the verdict becomes Purchasable. Adding a price does not auto-sync — click Sync to Stripe whenever a product or its active price is not yet mapped.

If Stripe is not configured for the deployment (no API key), the panel says so on the Stripe-mapped precondition instead of a dead "missing" marker — pricing simply cannot be Stripe-mapped, though grant-based access still works without Stripe.

Operator guidelines

Do in the member console

  • Create and manage products, prices, and entitlement sets
  • Monitor sync status in the operator panel
  • Create grants for admin-granted access (bypasses billing)

Do not do in Stripe

  • Do not create products or prices in the Stripe Dashboard. They will not be recognized by the member console.
  • Do not delete products or prices in Stripe. Deactivate them in the member console instead.
  • Do not modify subscription quantities or prices in Stripe. Changes should flow through the member console.

Acceptable in Stripe

  • View payment details, invoices, and customer records
  • Handle disputes and issue refunds (until member console tooling exists)
  • Configure tax settings, payment method types, and Stripe-level features the member console does not manage