Project: ledger-api · Branch: feat/stripe-webhooks · Mode: default · Model: gpt-5-codex
Summary
Made Stripe webhook handling idempotent: every event id is recorded in a processed_events table inside the same transaction as the side effect, so retries from Stripe can never double-credit an invoice.
Conversation
Turn 1 — User
Stripe retries webhooks. Make sure we never apply the same event twice.
Turn 1 — Assistant
Insert the event id into processed_events (unique) in the same transaction as the invoice update; on a unique-violation, return 200 and skip. Signature verification stays first.
@router.post("/webhooks/stripe")
async def stripe_webhook(request: Request, db: Session = Depends(get_db)):
event = verify_signature(await request.body(), request.headers)
try:
with db.begin():
db.add(ProcessedEvent(id=event.id))
apply_event(db, event)
except IntegrityError:
return {"status": "duplicate"} # already handled
return {"status": "ok"}
Tools used in this turn:
Edit: ledger/webhooks.pyWrite: migrations/versions/0004_processed_events.pyBash: pytest tests/test_webhooks.py -q — 6 passed
Connections
- [[ledger-api]]
- [[Stripe]]
- [[Idempotency]]
- [[PostgreSQL]]