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>
This commit is contained in:
parent
ced6ca2b2b
commit
902bafe7f2
1 changed files with 23 additions and 0 deletions
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}")
|
@tickets_api_router.websocket("/ws/{payment_hash}")
|
||||||
async def websocket_endpoint(payment_hash: str, websocket: WebSocket) -> None:
|
async def websocket_endpoint(payment_hash: str, websocket: WebSocket) -> None:
|
||||||
await websocket.accept()
|
await websocket.accept()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue