Tristan578

stripe-webhooks

SpawnForge Stripe webhook patterns — idempotent refunds, CTE atomic claims, neonSql transaction ordering, token billing. Auto-loads when editing billing code.

Tristan578 12 1 Actualitzat fa 1 mes
GitHub

Instal·la

npx skillscat add tristan578/project-forge/claude-skills-stripe-webhooks

Instal·la des del registre de SkillsCat.

SKILL.md

Stripe Webhook Patterns — SpawnForge

Critical patterns (from real bugs)

1. Atomic CTE claim for refunds (PF-7514)

Never read refundedCents in JS then update in a separate query. Use a single CTE:

WITH old AS (SELECT id, refunded_cents, tokens, amount_cents FROM token_purchases WHERE id = $1)
UPDATE token_purchases SET refunded_cents = $2 FROM old
WHERE token_purchases.id = $1 AND old.refunded_cents < $2
RETURNING old.tokens, old.amount_cents, ($2 - old.refunded_cents) AS increment_cents

If 0 rows returned → concurrent request already claimed. Return immediately.

2. neonSql transaction ordering

INSERT audit record BEFORE UPDATE user balance — PostgreSQL sees prior statements' effects within neonSql.transaction([...]).

3. Idempotent refundTokens

Check metadata->>'refundedUsageId' before crediting. Without this, server + client both refunding the same failed job doubles credits.

4. Never use db.transaction()

neon-http driver throws. Use getNeonSql() → neonSql.transaction([...statements]).

References

  • web/src/app/api/stripe/webhook/route.ts — the live webhook handler implementing the patterns above
  • web/src/lib/tokens/service.ts — refundTokens() idempotency + balance deduction
  • Stripe API version is pinned to 2026-08-26.dahlia in web/src/lib/billing/stripe-client.ts (must match the installed SDK)