Payments

Stripe setup

End-to-end Stripe configuration for both ToT (direct charges) and Storefront (Connect Express). Walk through this once per environment — test mode for development, live mode for production.

The two payment models

ThisOrThatStorefront
ModelDirect charges on platformStripe Connect Express
Funds settle intoYour platform accountOperator's Connect account
Capture methodManual (sale-lock safety)Automatic
Checkout typePayment Intent (custom UI)Stripe-hosted Checkout Session
Platform feeBuilt into spread (Pull/Flip)Application fee (3% default)
Per-operator setupNone — single accountExpress onboarding per shop

1 · Create your Stripe account

  1. Sign up at dashboard.stripe.com/register
  2. Complete the platform-business profile (this is the meta-account that owns the platform fee)
  3. Enable Connect in Settings → Connect — needed for the Storefront's per-shop accounts
  4. Set your platform name and statement descriptor (Settings → Public details)

2 · Get test-mode keys

  1. In Stripe dashboard, ensure "Test mode" toggle (top-right) is ON
  2. Go to Developers → API keys
  3. Copy:
    • Publishable keypk_test_...
    • Secret keysk_test_... (click "Reveal")
🔑 Where to paste them

On Railway → ToT service → Variables tab:

STRIPE_SECRET_KEY=sk_test_...
STRIPE_PUBLISHABLE_KEY=pk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...

On Railway → Storefront service → Variables:

STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...

3 · Set up webhooks

Stripe needs to call back when things happen — order paid, payment failed, refund issued. Without working webhooks, paid orders never flip to "paid" and labels can't print.

ToT webhook endpoint

  1. Stripe dashboard → Developers → Webhooks → Add endpoint
  2. Endpoint URL: https://thisorthat.slabtrack.io/api/stripe/webhook
  3. Events to listen for:
    • checkout.session.completed
    • payment_intent.succeeded
    • payment_intent.payment_failed
    • payment_intent.canceled
    • charge.refunded
    • charge.dispute.created
    • charge.dispute.closed
  4. Save → click the new endpoint → reveal Signing secretwhsec_...
  5. Paste into Railway as STRIPE_WEBHOOK_SECRET on the ToT service

Storefront webhook endpoint

  1. Stripe dashboard → Developers → Webhooks → Add endpoint
  2. Endpoint URL: https://storefront.slabtrack.io/api/stripe/webhook
  3. Listen on "Events on Connected accounts" — toggle this checkbox
  4. Events:
    • account.updated
    • checkout.session.completed
    • checkout.session.async_payment_succeeded
    • checkout.session.async_payment_failed
    • checkout.session.expired
    • payment_intent.payment_failed
    • payment_intent.canceled
    • charge.refunded
  5. Save → reveal signing secret → paste as STRIPE_WEBHOOK_SECRET on the Storefront service
⚠ Each environment gets its own webhook

Test-mode and live-mode webhooks have different signing secrets. When you flip to live, create new endpoints (with the production URLs) and update STRIPE_WEBHOOK_SECRET on Railway to the live endpoint's secret.

4 · Operator Stripe Connect onboarding (Storefront only)

Each shop owner needs to onboard their own Stripe account so funds settle directly into theirs. The flow is:

  1. Operator visits /dashboard/[slug]/settings
  2. Clicks "Connect Stripe Account"
  3. Storefront calls POST /api/stripe/connect/onboard which creates a Stripe Express account + onboarding link
  4. Operator is redirected to Stripe's hosted onboarding (provides bank info, identity, etc.)
  5. Stripe redirects back to /api/stripe/connect/return
  6. account.updated webhook fires → flips stripeChargesEnabled + stripeDetailsSubmitted on the Storefront row
  7. Public storefront's buy buttons activate
💡 Test the operator flow with Stripe test data

In test mode, Stripe accepts "Skip this step" for most fields. You can onboard a test operator in 30 seconds. For dev, use these test values:

  • Test bank: routing 110000000, account 000123456789
  • Test SSN: 000-00-0000
  • Test debit card: 4000056655665556

5 · Test card numbers

CardBehavior
4242 4242 4242 4242Always succeeds. Use for happy-path tests.
4000 0000 0000 9995Insufficient funds — declines after auth.
4000 0000 0000 0002Generic decline at auth time.
4000 0027 6000 3184Requires 3D Secure auth (test the SCA flow).
4000 0000 0000 9979Stolen card.

For all test cards: any future expiry date, any 3-digit CVC, any 5-digit ZIP.

6 · Going live

  1. Toggle Stripe dashboard to Live mode
  2. Activate your account (Stripe asks for business verification)
  3. Get live keys: sk_live_... and pk_live_...
  4. Create live webhook endpoints (same URLs but they'll get new secrets in live mode)
  5. Replace ALL Stripe-related env vars on Railway with live equivalents
  6. Trigger Railway redeploys so the new secrets load
  7. Run a real $1 purchase end-to-end before announcing launch
⚠ Live mode is real money

Once you flip to sk_live_, every charge is real. The test card 4242... will fail. Always test in test mode first; only flip to live when you've confirmed: webhook fires → Order flips → label can be purchased → buyer email sends.

Refund flow

Both ToT and Storefront support full + partial refunds via the operator dashboard.

Both routes hit Stripe's refunds API with reverse_transfer + refund_application_fee (Storefront only) so the platform's 3% fee gets returned alongside the buyer's principal. Idempotency key on the refund call prevents double-refund from a misclick.

Production readiness checklist