Webhooks in Practice
Webhooks tell your server when something changes — a ticket moves, a KYC finishes, a limit is updated. This page explains how delivery behaves so your handler processes each event once and never misses one. Registering a URL is in Notifier Webhooks; every event and payload is in Webhook Events.
What arrives
Each delivery is a POST to your URL with a JSON body like:
{
"event": {
"id": "00000000-0000-0000-0000-000000000000",
"accountId": "11111111-1111-1111-1111-111111111111",
"subscription": "TICKET",
"data": {
"type": "DELIVERY-SUCCESS",
"ticket": { "id": "...", "status": "PAID", "...": "..." }
},
"createdAt": "2026-10-22T18:06:50.808725Z",
"EventType": ""
}
}
event.ididentifies the event. It stays the same when the event is delivered again or resent.event.accountIdis the account the event is about: the sub-account for sub-account operations, otherwise the main account.data.typeis the event name. Names use hyphens:DELIVERY-SUCCESS,TICKET-COMPLETE,DEPOSIT-FAILED.- Ticket events carry the whole ticket in
data.ticket, with the same fields asGET /v2/account/tickets/{id}. - The
Signatureheader lets you check the event came from Avenia — see Verifying Authenticity.
How to handle them
- Answer
2xxfast. Any2xxcounts as received; the body you return is ignored. Store the event and process it afterwards, so you answer within a few seconds. - Deduplicate by
event.id. The same event can arrive more than once. - Don't rely on order. Events of one ticket are sent in parallel and can arrive out of order. Decide from the ticket
statusin the payload (or read the ticket), not from the order of arrival. - Read the final status.
TICKET-COMPLETEarrives for success and failure alike. Checkdata.ticket.statusandfailureReason.
When your endpoint fails
- If your endpoint answers with a non-
2xxstatus, the event is not sent again. It is recorded as an unacknowledged attempt. - If your endpoint can't be reached (connection refused, no response), the delivery is retried briefly. If it still fails, no attempt is recorded for that event.
So after an outage on your side, recover what you missed:
- List the events created since the outage started:
GET /v2/notifications/webhooks/events?createdAfter=<epoch milliseconds>(optionally&subscription=TICKET, and&subAccountId=for a sub-account). Compare theirids with the events you already processed. This finds events whether or not your endpoint ever answered. - For non-
2xxanswers,GET /v2/notifications/webhooks/attempts?unackedOnly=truelists them — see Webhook Attempts. - Resend a ticket's events:
POST /v2/account/tickets/{ticketId}/resend-webhooks(add?subAccountId=for a sub-account's ticket). It sends all of that ticket's events again with their originalevent.id; like any delivery, they can arrive in any order. Tickets older than 30 days can't be resent. - Or skip the webhook: read the ticket with
GET /v2/account/tickets/{ticketId}. - Mark attempts you've handled with
PATCH /v2/notifications/webhooks/attempts.
Questions that come up
Is there an event when an UNPAID ticket expires? No. The ticket stays UNPAID; see Expired tickets.
I received ticket events for a PIX I never created a ticket for. A PIX sent to your static key or BR Code creates a ticket automatically, with reason Pix deposit without ticket, and sends the usual events. An on-chain deposit to your deposit address does the same with Blockchain deposit without ticket.
How do I tell a pay-in from a payout? There's no direction field. Read data.ticket.quote.inputPaymentMethod and outputPaymentMethod, or which sender/receiver block the ticket has (brazilianFiatSenderInfo for a PIX received, brazilianFiatReceiverInfo for a PIX sent).
Where is the payer's tax ID? In the sender block of the ticket, for example data.ticket.brazilianFiatSenderInfo for a PIX deposit.
Can I register more than one URL? Up to 3 per account, HTTPS only. Each can subscribe to a subset of events or to *.