Get your API key
API reference

Deliveries

Re-deliver a stored message to its webhook. See Delivery & reliability for a guided walk-through.

Auth: Session token · Base URL: https://api.mailkite.dev

Endpoints

Each row expands to its request and response schema. The address bar follows along, so any endpoint can be linked to directly.

POST /api/deliveries/:id/retry Re-deliver a stored message to its webhook.

Re-deliver a stored message to its webhook.

Response body

retry-delivery-response.json

POST /api/deliveries/:id/retry — the outcome and the NEW delivery row the retry appended (history is append-only; the original row is untouched).

FieldTypeNotes
ok req booleanThe endpoint accepted the redelivery.
status req integerHTTP status the endpoint returned (0 when the request failed before a response).
delivery req deliveryThe new delivery row recording this retry.
delivery.id req stringDelivery id (dlv_…).
delivery.message_id req stringThe message this delivery carries (msg_…).
delivery.route_id req stringThe route whose webhook was targeted (rte_…).
delivery.url req stringThe webhook URL the body was POSTed to.
delivery.status req "pending" · "delivered" · "failed" · "paused"Current state of this delivery.
delivery.attempts req integerHow many attempts this delivery has made.
delivery.last_status_codeinteger · nullHTTP status of the most recent attempt.
delivery.next_retry_atinteger · nullWhen the auto-retry cron will re-attempt a failed delivery; null when nothing is due, in Unix epoch milliseconds (UTC); null when it has never happened.
delivery.retry_attemptsintegerHow many automatic retries have been scheduled so far.
delivery.created_at req integerWhen the delivery was created, in Unix epoch milliseconds (UTC).
delivery.updated_at req integerWhen the delivery last changed, in Unix epoch milliseconds (UTC).
POST /api/deliveries/retry Replay a whole selection of webhook deliveries in one call — the bulk form of retryDelivery. Pass `deliveryIds` (replay those exact deliveries), `messageIds` (replay each message's most recent delivery per route), and/or `threadIds` (expanded server-side to every message in the conversation); they combine. At most 50 ids per request, so send larger selections as sequential batches. Always answers 200 with a per-id `results` array — one unreachable endpoint never hides the outcomes of the rest — so branch on `ok` and `results`, not the HTTP status. An id you don't own is reported as skipped with reason `not_found`, exactly as the single-delivery endpoint 404s.

Replay a whole selection of webhook deliveries in one call — the bulk form of retryDelivery. Pass `deliveryIds` (replay those exact deliveries), `messageIds` (replay each message's most recent delivery per route), and/or `threadIds` (expanded server-side to every message in the conversation); they combine. At most 50 ids per request, so send larger selections as sequential batches. Always answers 200 with a per-id `results` array — one unreachable endpoint never hides the outcomes of the rest — so branch on `ok` and `results`, not the HTTP status. An id you don't own is reported as skipped with reason `not_found`, exactly as the single-delivery endpoint 404s.

Request body

replay-request.json

Which stored deliveries to re-POST. Pass at least one of `deliveryIds`, `messageIds`, or `threadIds` — they combine, and the same endpoint is never hit twice for one message in a single call. At most 50 ids per request (threads are expanded to their messages BEFORE the cap applies); send larger selections as sequential batches.

FieldTypeNotes
deliveryIdsstring[]Replay exactly these delivery rows (dlv_…), to the URL each recorded.
messageIdsstring[]For each message (msg_…), replay its most recent delivery per route. A message no webhook ever fired for is reported as skipped with reason `no_delivery`.
threadIdsstring[]Conversation ids — expanded server-side to every message in the thread, then treated as `messageIds`. Lets a thread-grouped list select whole conversations.

Response body

replay-response.json

The outcome of a batch replay. Always 200 with per-id detail — one unreachable endpoint must not hide the outcomes of the rest — so check `ok` and `results`, not the HTTP status.

FieldTypeNotes
ok req booleanEvery requested id succeeded. False if anything failed or was skipped.
requested req integerHow many replays this call accounted for — equal to `results.length`.
delivered req integerHow many endpoints accepted the replay.
failed req integerHow many were attempted and rejected (or timed out).
skipped req integerHow many ids were never attempted — unresolvable, or a message with no delivery to replay.
results req replay-result[]One row per requested id, in no guaranteed order.
results[].messageId req string · nullThe message replayed (msg_…); null when the id could not be resolved to one.
results[].routeId req string · nullThe route whose webhook was targeted (rte_…); null when nothing was attempted.
results[].deliveryId req string · nullThe NEW delivery row this replay appended (dlv_…); null when nothing was attempted.
results[].ok req booleanThe endpoint accepted this replay.
results[].status req integer · nullHTTP status the endpoint returned; null when the request failed before a response, or nothing was attempted.
results[].reason req string · nullWhy it did not succeed. `not_found` = no such id on this account (a foreign id reads the same way, deliberately). `no_delivery` = the message has no webhook delivery to replay. Otherwise the delivery's own classification: `http`, `timeout`, `network`, `redirect`, or `no-ack`. Null when ok.
GET /api/deliveries/:id/attempts Every captured attempt for one delivery, newest first: the request headers and payload we POSTed, and the status, headers, and body that came back. This is the per-attempt record behind a webhook post-mortem, fetched without pulling the whole message. Captures are retained for 45 days.

Every captured attempt for one delivery, newest first: the request headers and payload we POSTed, and the status, headers, and body that came back. This is the per-attempt record behind a webhook post-mortem, fetched without pulling the whole message. Captures are retained for 45 days.

Response body

delivery-attempts-response.json

Every captured attempt for one delivery, newest first — the request we sent and the response we got back. Captures are retained for 45 days.

FieldTypeNotes
attempts req delivery-attempt[]Attempts for this delivery, newest first.
attempts[].id req stringAttempt id (att_…).
attempts[].delivery_id req stringThe delivery this attempt belongs to (dlv_…).
attempts[].message_id req stringThe message delivered (msg_…).
attempts[].attempt_number req integer1-based attempt counter within the delivery.
attempts[].ok req 0 · 11 when the attempt succeeded.
attempts[].reasonstring · nullFailure classification when not ok (e.g. 'http_5xx', 'timeout', 'no-ack').
attempts[].request_headersstring · nullRequest headers we sent, as a JSON string (content-type, x-mailkite-signature, x-mailkite-timestamp). Null for attempts recorded before capture existed.
attempts[].request_bodystring · nullThe JSON payload we POSTed, truncated to ~4KB. Null for attempts recorded before capture existed.
attempts[].response_statusinteger · nullHTTP status the endpoint returned.
attempts[].response_headersstring · nullResponse headers as a JSON string.
attempts[].response_bodystring · nullResponse body, truncated to ~4KB.
attempts[].duration_msinteger · nullRound-trip time of the attempt.
attempts[].requested_at req integerWhen the attempt started, in Unix epoch milliseconds (UTC).
attempts[].created_at req integerWhen the audit row was recorded, in Unix epoch milliseconds (UTC).