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.py - Write: migrations/versions/0004_processed_events.py - Bash: pytest tests/test_webhooks.py -q — 6 passed Connections - ledger-api - Stripe - Idempotency - PostgreSQL