Routes
Inbound routing rules — match an address and deliver it to a webhook, agent, or forward. See Inbound webhooks 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.
GET /api/routes List inbound routing rules.
List inbound routing rules.
An inbound routing rule: which addresses it matches and what happens to matching mail (webhook POST, forward, store, drop, or an inbox agent). The per-route signing secret is returned ONCE on create and via GET /api/domains/:id/webhook/secret — list responses omit it.
| Field | Type | Notes |
|---|---|---|
| id req | string | Route id (rte_…). |
| user_id req | string | Owning account (usr_…). |
| match_pattern req | string | Which recipient addresses this route matches: an exact address, `*@domain`, a prefix pattern like `ticket+*@domain`, or a `/regex/`. |
| action req | "webhook" · "forward" · "store" · "drop" · "agent" | What happens to a matching message. |
| destination | string · null | Webhook URL or forward address. null for store/drop/agent actions. |
| agent_prompt | string · null | Instructions for the built-in inbox agent (action 'agent' only). |
| agent_forward_to | string · null | Extra addresses the inbox agent's forward tool may reach, as a JSON array string. null = owner-controlled addresses only. |
| agent_context | "message" · "thread" · "sender" · null | How much mail the inbox agent may read once the sender is verified. null = 'message' (just the inbound email). |
| active req | 0 · 1 | 1 while the route is enabled. |
| ack_mode req | "lenient" · "ack" | Webhook acknowledgement strictness: 'lenient' accepts any 2xx; 'ack' also requires {"status":"ok"} (or the x-mailkite-ack header) on every delivery. |
| last_status | "ok" · "fail" · "running" · "timeout" · null | Outcome of the route's most recent action. null = never exercised. |
| last_status_message | string · null | Human-readable detail of the last outcome (e.g. 'HTTP 500'). |
| last_status_code | integer · null | Transport status code of the last outcome, when relevant. |
| last_status_at | integer · null | When the last outcome landed, in Unix epoch milliseconds (UTC); null when it has never happened. |
| consecutive_failures | integer | Current failing streak (0 when healthy). |
| first_failed_at | integer · null | When the current failing streak began, in Unix epoch milliseconds (UTC); null when it has never happened. |
| unhealthy_notified_at | integer · null | When the owner was emailed about the current streak, in Unix epoch milliseconds (UTC); null when it has never happened. |
| signing_secret | string · null | Per-route webhook signing secret (whsec_…). Returned on create; read later via GET /api/domains/:id/webhook/secret. null until first read lazily creates it. |
| created_at req | integer | When the route was created, in Unix epoch milliseconds (UTC). |
An actual array of results, recorded from the conformance suite.
[
{
"id": "rte_4Bn8XcVm",
"user_id": "usr_7Fj3MnQw",
"match_pattern": "*@myapp.ai",
"action": "webhook",
"destination": "https://myapp.ai/hooks/mailkite",
"agent_prompt": null,
"agent_forward_to": null,
"agent_context": null,
"active": 1,
"ack_mode": "lenient",
"last_status": "ok",
"last_status_message": null,
"last_status_code": 200,
"last_status_at": 1769817600000,
"consecutive_failures": 0,
"first_failed_at": null,
"unhealthy_notified_at": null,
"signing_secret": null,
"created_at": 1769731200000
}
] {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/route.json",
"title": "Route",
"description": "An inbound routing rule: which addresses it matches and what happens to matching mail (webhook POST, forward, store, drop, or an inbox agent). The per-route signing secret is returned ONCE on create and via GET /api/domains/:id/webhook/secret — list responses omit it.",
"type": "object",
"required": [
"id",
"user_id",
"match_pattern",
"action",
"active",
"ack_mode",
"created_at"
],
"properties": {
"id": {
"type": "string",
"description": "Route id (rte_…).",
"examples": [
"rte_4Bn8XcVm"
]
},
"user_id": {
"type": "string",
"description": "Owning account (usr_…).",
"examples": [
"usr_7Fj3MnQw"
]
},
"match_pattern": {
"type": "string",
"description": "Which recipient addresses this route matches: an exact address, `*@domain`, a prefix pattern like `ticket+*@domain`, or a `/regex/`.",
"examples": [
"*@myapp.ai"
]
},
"action": {
"type": "string",
"enum": [
"webhook",
"forward",
"store",
"drop",
"agent"
],
"description": "What happens to a matching message."
},
"destination": {
"type": [
"string",
"null"
],
"description": "Webhook URL or forward address. null for store/drop/agent actions.",
"examples": [
"https://myapp.ai/hooks/mailkite"
]
},
"agent_prompt": {
"type": [
"string",
"null"
],
"description": "Instructions for the built-in inbox agent (action 'agent' only)."
},
"agent_forward_to": {
"type": [
"string",
"null"
],
"description": "Extra addresses the inbox agent's forward tool may reach, as a JSON array string. null = owner-controlled addresses only."
},
"agent_context": {
"type": [
"string",
"null"
],
"enum": [
"message",
"thread",
"sender",
null
],
"description": "How much mail the inbox agent may read once the sender is verified. null = 'message' (just the inbound email)."
},
"active": {
"type": "integer",
"enum": [
0,
1
],
"description": "1 while the route is enabled."
},
"ack_mode": {
"type": "string",
"enum": [
"lenient",
"ack"
],
"description": "Webhook acknowledgement strictness: 'lenient' accepts any 2xx; 'ack' also requires {\"status\":\"ok\"} (or the x-mailkite-ack header) on every delivery."
},
"last_status": {
"type": [
"string",
"null"
],
"enum": [
"ok",
"fail",
"running",
"timeout",
null
],
"description": "Outcome of the route's most recent action. null = never exercised."
},
"last_status_message": {
"type": [
"string",
"null"
],
"description": "Human-readable detail of the last outcome (e.g. 'HTTP 500')."
},
"last_status_code": {
"type": [
"integer",
"null"
],
"description": "Transport status code of the last outcome, when relevant.",
"examples": [
200
]
},
"last_status_at": {
"type": [
"integer",
"null"
],
"description": "When the last outcome landed, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"consecutive_failures": {
"type": "integer",
"description": "Current failing streak (0 when healthy)."
},
"first_failed_at": {
"type": [
"integer",
"null"
],
"description": "When the current failing streak began, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"unhealthy_notified_at": {
"type": [
"integer",
"null"
],
"description": "When the owner was emailed about the current streak, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"signing_secret": {
"type": [
"string",
"null"
],
"description": "Per-route webhook signing secret (whsec_…). Returned on create; read later via GET /api/domains/:id/webhook/secret. null until first read lazily creates it."
},
"created_at": {
"type": "integer",
"description": "When the route was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
} POST /api/routes Create a route (match, action, destination).
Create a route (match, action, destination).
Request body
create-route-request.json| Field | Type | Notes |
|---|---|---|
| match req | string | Address pattern: exact, *@domain, addr+*@domain, or /regex/. |
| action | "webhook" · "forward" · "store" · "drop" · "agent" | What to do with matching mail. Defaults to webhook. |
| destination | string | Required for action webhook (URL) or forward (address). |
| agentPrompt | string | Required for action agent — instructions for the inbox agent. |
| agentForwardTo | string[] | For action agent: addresses the inbox agent's forward tool may send to. The agent can always forward to your account email and any address on a verified domain you own; this adds extra approved addresses (e.g. an escalation inbox). |
| agentContext | "message" · "thread" · "sender" | For action agent: how much mail the agent may read once the sender is verified (they replied to an earlier agent message from a DMARC-passing address). 'message' (default) = only the incoming email; 'thread' = this conversation; 'sender' = all past mail with this sender. |
| forwardSpam | boolean | For action forward: also re-send mail scored as spam. Defaults to false — a forward re-sends over our own outbound infrastructure, so spam-verdicted mail is held (event forward.spam_held) rather than relayed. Set true if you would rather receive spam than risk missing anything; either way the message is stored and still fires webhook/agent routes. |
The smallest body that makes this call — every other field is optional.
{
"match": "*@app.mailkite.dev",
"action": "webhook",
"destination": "https://app.com/hooks"
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/create-route-request.json",
"title": "Create route request body",
"type": "object",
"required": [
"match"
],
"additionalProperties": false,
"properties": {
"match": {
"type": "string",
"description": "Address pattern: exact, *@domain, addr+*@domain, or /regex/."
},
"action": {
"type": "string",
"enum": [
"webhook",
"forward",
"store",
"drop",
"agent"
],
"description": "What to do with matching mail. Defaults to webhook."
},
"destination": {
"type": "string",
"description": "Required for action webhook (URL) or forward (address)."
},
"agentPrompt": {
"type": "string",
"description": "Required for action agent — instructions for the inbox agent."
},
"agentForwardTo": {
"type": "array",
"items": {
"type": "string"
},
"description": "For action agent: addresses the inbox agent's forward tool may send to. The agent can always forward to your account email and any address on a verified domain you own; this adds extra approved addresses (e.g. an escalation inbox)."
},
"agentContext": {
"type": "string",
"enum": [
"message",
"thread",
"sender"
],
"description": "For action agent: how much mail the agent may read once the sender is verified (they replied to an earlier agent message from a DMARC-passing address). 'message' (default) = only the incoming email; 'thread' = this conversation; 'sender' = all past mail with this sender."
},
"forwardSpam": {
"type": "boolean",
"description": "For action forward: also re-send mail scored as spam. Defaults to false — a forward re-sends over our own outbound infrastructure, so spam-verdicted mail is held (event forward.spam_held) rather than relayed. Set true if you would rather receive spam than risk missing anything; either way the message is stored and still fires webhook/agent routes."
}
}
} Response body
route.jsonAn inbound routing rule: which addresses it matches and what happens to matching mail (webhook POST, forward, store, drop, or an inbox agent). The per-route signing secret is returned ONCE on create and via GET /api/domains/:id/webhook/secret — list responses omit it.
| Field | Type | Notes |
|---|---|---|
| id req | string | Route id (rte_…). |
| user_id req | string | Owning account (usr_…). |
| match_pattern req | string | Which recipient addresses this route matches: an exact address, `*@domain`, a prefix pattern like `ticket+*@domain`, or a `/regex/`. |
| action req | "webhook" · "forward" · "store" · "drop" · "agent" | What happens to a matching message. |
| destination | string · null | Webhook URL or forward address. null for store/drop/agent actions. |
| agent_prompt | string · null | Instructions for the built-in inbox agent (action 'agent' only). |
| agent_forward_to | string · null | Extra addresses the inbox agent's forward tool may reach, as a JSON array string. null = owner-controlled addresses only. |
| agent_context | "message" · "thread" · "sender" · null | How much mail the inbox agent may read once the sender is verified. null = 'message' (just the inbound email). |
| active req | 0 · 1 | 1 while the route is enabled. |
| ack_mode req | "lenient" · "ack" | Webhook acknowledgement strictness: 'lenient' accepts any 2xx; 'ack' also requires {"status":"ok"} (or the x-mailkite-ack header) on every delivery. |
| last_status | "ok" · "fail" · "running" · "timeout" · null | Outcome of the route's most recent action. null = never exercised. |
| last_status_message | string · null | Human-readable detail of the last outcome (e.g. 'HTTP 500'). |
| last_status_code | integer · null | Transport status code of the last outcome, when relevant. |
| last_status_at | integer · null | When the last outcome landed, in Unix epoch milliseconds (UTC); null when it has never happened. |
| consecutive_failures | integer | Current failing streak (0 when healthy). |
| first_failed_at | integer · null | When the current failing streak began, in Unix epoch milliseconds (UTC); null when it has never happened. |
| unhealthy_notified_at | integer · null | When the owner was emailed about the current streak, in Unix epoch milliseconds (UTC); null when it has never happened. |
| signing_secret | string · null | Per-route webhook signing secret (whsec_…). Returned on create; read later via GET /api/domains/:id/webhook/secret. null until first read lazily creates it. |
| created_at req | integer | When the route was created, in Unix epoch milliseconds (UTC). |
An actual response, recorded from the conformance suite.
{
"id": "rte_4Bn8XcVm",
"user_id": "usr_7Fj3MnQw",
"match_pattern": "*@myapp.ai",
"action": "webhook",
"destination": "https://myapp.ai/hooks/mailkite",
"agent_prompt": null,
"agent_forward_to": null,
"agent_context": null,
"active": 1,
"ack_mode": "lenient",
"last_status": "ok",
"last_status_message": null,
"last_status_code": 200,
"last_status_at": 1769817600000,
"consecutive_failures": 0,
"first_failed_at": null,
"unhealthy_notified_at": null,
"signing_secret": null,
"created_at": 1769731200000
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/route.json",
"title": "Route",
"description": "An inbound routing rule: which addresses it matches and what happens to matching mail (webhook POST, forward, store, drop, or an inbox agent). The per-route signing secret is returned ONCE on create and via GET /api/domains/:id/webhook/secret — list responses omit it.",
"type": "object",
"required": [
"id",
"user_id",
"match_pattern",
"action",
"active",
"ack_mode",
"created_at"
],
"properties": {
"id": {
"type": "string",
"description": "Route id (rte_…).",
"examples": [
"rte_4Bn8XcVm"
]
},
"user_id": {
"type": "string",
"description": "Owning account (usr_…).",
"examples": [
"usr_7Fj3MnQw"
]
},
"match_pattern": {
"type": "string",
"description": "Which recipient addresses this route matches: an exact address, `*@domain`, a prefix pattern like `ticket+*@domain`, or a `/regex/`.",
"examples": [
"*@myapp.ai"
]
},
"action": {
"type": "string",
"enum": [
"webhook",
"forward",
"store",
"drop",
"agent"
],
"description": "What happens to a matching message."
},
"destination": {
"type": [
"string",
"null"
],
"description": "Webhook URL or forward address. null for store/drop/agent actions.",
"examples": [
"https://myapp.ai/hooks/mailkite"
]
},
"agent_prompt": {
"type": [
"string",
"null"
],
"description": "Instructions for the built-in inbox agent (action 'agent' only)."
},
"agent_forward_to": {
"type": [
"string",
"null"
],
"description": "Extra addresses the inbox agent's forward tool may reach, as a JSON array string. null = owner-controlled addresses only."
},
"agent_context": {
"type": [
"string",
"null"
],
"enum": [
"message",
"thread",
"sender",
null
],
"description": "How much mail the inbox agent may read once the sender is verified. null = 'message' (just the inbound email)."
},
"active": {
"type": "integer",
"enum": [
0,
1
],
"description": "1 while the route is enabled."
},
"ack_mode": {
"type": "string",
"enum": [
"lenient",
"ack"
],
"description": "Webhook acknowledgement strictness: 'lenient' accepts any 2xx; 'ack' also requires {\"status\":\"ok\"} (or the x-mailkite-ack header) on every delivery."
},
"last_status": {
"type": [
"string",
"null"
],
"enum": [
"ok",
"fail",
"running",
"timeout",
null
],
"description": "Outcome of the route's most recent action. null = never exercised."
},
"last_status_message": {
"type": [
"string",
"null"
],
"description": "Human-readable detail of the last outcome (e.g. 'HTTP 500')."
},
"last_status_code": {
"type": [
"integer",
"null"
],
"description": "Transport status code of the last outcome, when relevant.",
"examples": [
200
]
},
"last_status_at": {
"type": [
"integer",
"null"
],
"description": "When the last outcome landed, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"consecutive_failures": {
"type": "integer",
"description": "Current failing streak (0 when healthy)."
},
"first_failed_at": {
"type": [
"integer",
"null"
],
"description": "When the current failing streak began, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"unhealthy_notified_at": {
"type": [
"integer",
"null"
],
"description": "When the owner was emailed about the current streak, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"signing_secret": {
"type": [
"string",
"null"
],
"description": "Per-route webhook signing secret (whsec_…). Returned on create; read later via GET /api/domains/:id/webhook/secret. null until first read lazily creates it."
},
"created_at": {
"type": "integer",
"description": "When the route was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
} DELETE /api/routes/:id Delete an inbound routing rule by id. Pair with createRoute to register and tear down a webhook destination — e.g. an automation platform subscribing on enable and cleaning up on disable.
Delete an inbound routing rule by id. Pair with createRoute to register and tear down a webhook destination — e.g. an automation platform subscribing on enable and cleaning up on disable.
Response body
ok-response.jsonThe uniform acknowledgement for deletes and other actions with nothing else to report.
| Field | Type | Notes |
|---|---|---|
| ok req | true | Always true — a non-2xx error body is returned otherwise. |
An actual response, recorded from the conformance suite.
{
"ok": true
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/ok-response.json",
"title": "OK",
"description": "The uniform acknowledgement for deletes and other actions with nothing else to report.",
"type": "object",
"required": [
"ok"
],
"properties": {
"ok": {
"type": "boolean",
"const": true,
"description": "Always true — a non-2xx error body is returned otherwise."
}
}
} POST /api/routes/:id/deliver POST stored messages to one webhook route — including messages that arrived BEFORE the route existed, which no retry can reach (a retry replays an existing delivery row, and a new route has none). Use listRouteCandidates to find what a route could be sent. Webhook routes only: a forward would re-send real mail to a third party and an agent would re-spend model tokens, so both answer 400 `route_action`. At most 50 ids per request; same per-id `results` contract as retryDeliveries.
POST stored messages to one webhook route — including messages that arrived BEFORE the route existed, which no retry can reach (a retry replays an existing delivery row, and a new route has none). Use listRouteCandidates to find what a route could be sent. Webhook routes only: a forward would re-send real mail to a third party and an agent would re-spend model tokens, so both answer 400 `route_action`. At most 50 ids per request; same per-id `results` contract as retryDeliveries.
Request body
deliver-to-route-request.jsonWhich stored messages to POST to this route. Unlike a retry, these messages need no existing delivery on the route — this is how mail that arrived BEFORE the route existed reaches it. At most 50 ids per request.
| Field | Type | Notes |
|---|---|---|
| messageIds req | string[] | Stored messages (msg_…) to deliver to this route's webhook, in any order. |
The smallest body that makes this call — every other field is optional.
{
"messageIds": [
"msg_2Hk9QpVn4tLd",
"msg_5Tq1RvXz"
]
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/deliver-to-route-request.json",
"title": "Deliver to route request",
"description": "Which stored messages to POST to this route. Unlike a retry, these messages need no existing delivery on the route — this is how mail that arrived BEFORE the route existed reaches it. At most 50 ids per request.",
"type": "object",
"required": [
"messageIds"
],
"properties": {
"messageIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Stored messages (msg_…) to deliver to this route's webhook, in any order.",
"examples": [
[
"msg_2Hk9QpVn4tLd",
"msg_5Tq1RvXz"
]
]
}
}
} Response body
replay-response.jsonThe 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.
| Field | Type | Notes |
|---|---|---|
| ok req | boolean | Every requested id succeeded. False if anything failed or was skipped. |
| requested req | integer | How many replays this call accounted for — equal to `results.length`. |
| delivered req | integer | How many endpoints accepted the replay. |
| failed req | integer | How many were attempted and rejected (or timed out). |
| skipped req | integer | How 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 · null | The message replayed (msg_…); null when the id could not be resolved to one. |
| results[].routeId req | string · null | The route whose webhook was targeted (rte_…); null when nothing was attempted. |
| results[].deliveryId req | string · null | The NEW delivery row this replay appended (dlv_…); null when nothing was attempted. |
| results[].ok req | boolean | The endpoint accepted this replay. |
| results[].status req | integer · null | HTTP status the endpoint returned; null when the request failed before a response, or nothing was attempted. |
| results[].reason req | string · null | Why 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. |
An actual response, recorded from the conformance suite.
{
"ok": true,
"requested": 2,
"delivered": 2,
"failed": 0,
"skipped": 0,
"results": [
{
"messageId": "msg_2Hk9QpVn4tLd",
"routeId": "rte_4Bn8XcVm",
"deliveryId": "dlv_7Mn3PxQb",
"ok": true,
"status": 200,
"reason": null
},
{
"messageId": "msg_5Tq1RvXz",
"routeId": "rte_4Bn8XcVm",
"deliveryId": "dlv_9Wc4KdHp",
"ok": true,
"status": 200,
"reason": null
}
]
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/replay-response.json",
"title": "Replay response",
"description": "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.",
"type": "object",
"required": [
"ok",
"requested",
"delivered",
"failed",
"skipped",
"results"
],
"properties": {
"ok": {
"type": "boolean",
"description": "Every requested id succeeded. False if anything failed or was skipped."
},
"requested": {
"type": "integer",
"description": "How many replays this call accounted for — equal to `results.length`.",
"examples": [
12
]
},
"delivered": {
"type": "integer",
"description": "How many endpoints accepted the replay.",
"examples": [
10
]
},
"failed": {
"type": "integer",
"description": "How many were attempted and rejected (or timed out).",
"examples": [
1
]
},
"skipped": {
"type": "integer",
"description": "How many ids were never attempted — unresolvable, or a message with no delivery to replay.",
"examples": [
1
]
},
"results": {
"type": "array",
"items": {
"$ref": "replay-result.json"
},
"description": "One row per requested id, in no guaranteed order."
}
}
} GET /api/routes/:id/candidates Stored inbound messages this route could be asked to deliver, newest first — the preview for replaying mail to a route defined after that mail arrived. Each row carries `delivered_here`, so you can send a route only what it has never seen. Page with `before` (the response's `nextBefore`); because matching happens after a bounded scan, a page can come back shorter than `limit` while more still remain — keep going until `nextBefore` is null.
Stored inbound messages this route could be asked to deliver, newest first — the preview for replaying mail to a route defined after that mail arrived. Each row carries `delivered_here`, so you can send a route only what it has never seen. Page with `before` (the response's `nextBefore`); because matching happens after a bounded scan, a page can come back shorter than `limit` while more still remain — keep going until `nextBefore` is null.
Response body
route-candidates-response.jsonA page of messages one route could replay, newest first.
| Field | Type | Notes |
|---|---|---|
| messages req | route-candidate[] | Matching messages, newest first. |
| messages[].id req | string | Message id (msg_…) — pass this to deliverToRoute. |
| messages[].from_addr req | string | Sender address as stored. |
| messages[].to_addr req | string | Recipient the route's pattern matched. |
| messages[].subject req | string · null | Subject line, or null when the message carried none. |
| messages[].received_at req | integer | When the message arrived, in Unix epoch milliseconds (UTC). Also the paging cursor. |
| messages[].delivered_here req | 0 · 1 | 1 when this route already has a delivery for the message, 0 when it has never seen it. |
| nextBefore req | integer · null | Cursor for the next older page — pass as `before`. null when the scan reached the end. It is the last row SCANNED, not the last returned, so a page can legitimately come back shorter than `limit` while more remain. |
An actual response, recorded from the conformance suite.
{
"messages": [
{
"id": "msg_2Hk9QpVn4tLd",
"from_addr": "ada@example.com",
"to_addr": "support@myapp.ai",
"subject": "Invoice question",
"received_at": 1769731200000,
"delivered_here": 0
}
],
"nextBefore": null
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/route-candidates-response.json",
"title": "Route candidates response",
"description": "A page of messages one route could replay, newest first.",
"type": "object",
"required": [
"messages",
"nextBefore"
],
"properties": {
"messages": {
"type": "array",
"items": {
"$ref": "route-candidate.json"
},
"description": "Matching messages, newest first."
},
"nextBefore": {
"type": [
"integer",
"null"
],
"description": "Cursor for the next older page — pass as `before`. null when the scan reached the end. It is the last row SCANNED, not the last returned, so a page can legitimately come back shorter than `limit` while more remain.",
"examples": [
1769731200000
]
}
}
}