Events
Scopes: events:read to read, events:write to ask for one again. Live only.
GET /v1/events
Every event for your key's mode, newest first, whether or not it was delivered. This is how you catch up after an outage or before you had an endpoint.
Query: limit, starting_after, type (e.g. charge.succeeded).
json
{
"id": "ev_…",
"object": "event",
"type": "charge.succeeded",
"created": 1758013442,
"livemode": true,
"data": { "…": "…" },
"delivery": {
"state": "retrying",
"attempts": 3,
"attempts_remaining": 4,
"last_status": 502,
"last_response": "<html>Bad Gateway…",
"last_attempt_at": 1758015242,
"next_attempt_at": 1758022442
}
}delivery.state is one of pending · retrying · delivered · exhausted · unrouted (no endpoint was registered when it happened). It is the state of our conversation with your server, never the state of the payment — an exhausted charge.succeeded is still a payment you were paid. last_status: 0 means we could not reach you at all.
GET /v1/events/{id}
One event, with its delivery history.
POST /v1/events/{id}/retry
Ask for an event to be sent again. Allowed when it is delivered, exhausted or unrouted; the attempt count resets to zero. Returns the event. If it is already pending or retrying, ALREADY_QUEUED (409) — your intent is already true.
Nothing is sent by this call. It makes the event due, and the delivery job — the only thing that ever opens a socket to your server — picks it up within a minute. A replay behaves exactly like a first attempt because it is one.
A catch-up job
After any outage, page through GET /v1/events?type=charge.succeeded back to the last event you processed, and process anything you have not seen. Because delivery is at-least-once and your handler already deduplicates on id, the catch-up can be as generous as you like.