Rate-limit anonymous ticket creation; reap unpaid guest rows on cancel #38

Open
opened 2026-09-06 17:55:08 +00:00 by padreug · 0 comments
Owner

POST /events/api/v1/tickets/{event_id} is anonymous by design (guest checkout, #36) and has no rate limit: any caller can mint invoices and Stripe Checkout Sessions against an event (up to quantity=10 per call), creating unpaid rows and Stripe sessions in the organizer's account. Unpaid rows are only purged after 24 h (crud.purge_unpaid_tickets), so a burst can also exhaust visible capacity for a day if the client counts unpaid rows.

Proposal

  • Per-IP + per-event token bucket on ticket creation (e.g. 5/min, 30/h), 429 with Retry-After.
  • Cap outstanding unpaid rows per event from one IP/email.
  • Stripe ?checkout=cancelled return: the webapp could call a new DELETE /api/v1/tickets/pending/{payment_hash} (anonymous, only deletes unpaid rows for that hash) so an abandoned checkout frees the seats immediately instead of at the 24 h sweep.
  • Consider a captcha / proof-of-work only if abuse is observed.

Related: #29 (identity limits on free claims).

`POST /events/api/v1/tickets/{event_id}` is anonymous by design (guest checkout, #36) and has no rate limit: any caller can mint invoices and Stripe Checkout Sessions against an event (up to `quantity=10` per call), creating unpaid rows and Stripe sessions in the organizer's account. Unpaid rows are only purged after 24 h (`crud.purge_unpaid_tickets`), so a burst can also exhaust visible capacity for a day if the client counts unpaid rows. ## Proposal - Per-IP + per-event token bucket on ticket creation (e.g. 5/min, 30/h), 429 with `Retry-After`. - Cap outstanding **unpaid** rows per event from one IP/email. - Stripe `?checkout=cancelled` return: the webapp could call a new `DELETE /api/v1/tickets/pending/{payment_hash}` (anonymous, only deletes unpaid rows for that hash) so an abandoned checkout frees the seats immediately instead of at the 24 h sweep. - Consider a captcha / proof-of-work only if abuse is observed. Related: #29 (identity limits on free claims).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/events#38
No description provided.