feat: republish endpoints + polling + multi-ticket via N-rows model #16
1 changed files with 23 additions and 0 deletions
feat: POST /tickets/{event_id}/{payment_hash} polling endpoint
The webapp's useTicketPurchase polls this every 2s after firing
Pay with Wallet (or after presenting the QR) to confirm payment
before advancing to the ticket-QR success state. Without this
endpoint the post-payment poll loop returns 404 indefinitely and
the buyer never sees their ticket land — even though set_ticket_paid
fired on the invoice listener and the row is correctly marked paid
in the DB.
Returns {paid: bool, ticket_id?: str}. A missing or cross-event
ticket returns paid: false rather than 404 so the poll loop doesn't
need to special-case the not-yet-created race.
The WebSocket at /tickets/ws/{payment_hash} is more efficient for
push notifications — this POST is the fallback for clients that
can't open a relay-side socket.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
commit
902bafe7f2
23
views_api.py
23
views_api.py
|
|
@ -623,6 +623,29 @@ async def api_ticket_create(
|
|||
)
|
||||
|
||||
|
||||
@tickets_api_router.post("/{event_id}/{payment_hash}")
|
||||
async def api_ticket_payment_status(event_id: str, payment_hash: str) -> dict:
|
||||
"""Poll-style payment confirmation for a pending ticket.
|
||||
|
||||
The webapp's `useTicketPurchase` polls this every 2s after firing
|
||||
`Pay with Wallet` (or after presenting the QR for an external
|
||||
wallet) until `paid: true` comes back, then advances to the
|
||||
ticket-QR success state. The companion WebSocket at
|
||||
`/tickets/ws/{payment_hash}` is more efficient for pushes — this
|
||||
endpoint is the fallback for clients that can't open a relay-side
|
||||
socket.
|
||||
|
||||
Returns `{paid: bool, ticket_id?: str}` so the client can hand off
|
||||
to the ticket-detail flow without an extra GET. A missing /
|
||||
cross-event ticket returns `paid: false` rather than 404 so the
|
||||
poll loop doesn't have to special-case the not-yet-created race.
|
||||
"""
|
||||
ticket = await get_ticket(payment_hash)
|
||||
if not ticket or ticket.event != event_id:
|
||||
return {"paid": False}
|
||||
return {"paid": ticket.paid, "ticket_id": ticket.id}
|
||||
|
||||
|
||||
@tickets_api_router.websocket("/ws/{payment_hash}")
|
||||
async def websocket_endpoint(payment_hash: str, websocket: WebSocket) -> None:
|
||||
await websocket.accept()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue