Keys and webhooks
The credentials and endpoints this workspace has issued.
Keys and webhooks tools
| Tool | What it does |
|---|---|
| listApiKeys | Every API key this workspace has issued, what it may do and what it may send as, in a masked form that is enough to tell two keys apart and nothing more. Returned a page at a time. |
| listWebhooks | Every webhook endpoint this workspace has, where it posts, whether it is enabled and which events it asked for. Signing secrets are never shown. Returned a page at a time. |
| listWebhookEvents | Every event an endpoint can subscribe to, grouped by family, with a line saying when each one fires. |
| listApiKeyRequests | The request log of the workspace’s keys, newest first: method, path, status, error code, duration, IP and user agent. Narrow it to one key, to failed calls, to exact status codes, to one route, or to a window. Returned a page at a time. |
| listApiKeyActivity | What happened to the keys, newest first: created, updated, rotated, switched off or on, revoked, deleted and refused, and who did it. Returned a page at a time. |
| listWebhookDeliveries | The delivery log of one endpoint or of all of them, newest first, narrowed to delivered or failed and to a window. Returned a page at a time. |
| getWebhookDelivery | One delivery in full: the body that was sent, what the receiver answered, every try of the event, and whether a replay would be accepted. |
| replayWebhookDelivery | Send one event again, now, with its original id and a fresh signature. It always asks before it runs. |
| listWebhookActivity | What happened to the webhooks, newest first: created, changed, switched off or on, secret rotated, tested, replayed and removed, and who did it. Returned a page at a time. |
| getWebhook | One webhook endpoint: where it posts, whether it is on, which events it wants and which addresses it hears about. |
| createWebhook | Add a webhook endpoint with the events it wants and, if you like, allowlists. The signing secret is shown once. |
| updateWebhook | Change an endpoint’s URL, events, description or allowlists, or switch it on or off. |
| deleteWebhook | Remove a webhook endpoint. Its log and history stay. A chat always asks first. |
| rotateWebhookSecret | Give an endpoint a new signing secret, shown once. The old one keeps signing beside it for 24 hours. |
| testWebhook | Post one signed test event to an endpoint now and report what it answered. A chat always asks first. |
| getWebhookStats | How the deliveries went inside a window: attempts, delivered and failed, a series, the events sent and the response codes. |
| getApiKeyStats | What the keys did inside a window: the mail they sent, refused calls, requests and failures, the routes called most and the status codes. |
A secret is shown once, when a key or a webhook endpoint is made or its secret is rotated, and nothing recovers it afterwards. createWebhook and rotateWebhookSecret are the tools here that return one. After a rotation the old webhook secret keeps signing for 24 hours, so hand the receiver the new one within the day. The assistant in the app does not rotate secrets.
Keys are only read here. Rotating a key, switching it off, revoking it and changing what it may do need a permission no app is ever given, so they happen in Settings → API keys and with /keys on the REST API, where switching a key off is the reversible step and revoking it the permanent one.
There is no createApiKey here: issuing a key from inside a chat window is a quiet, wide change nobody sees afterwards, so keys are made in Settings and with POST /keys. The webhook tools act exactly as /webhooks on the REST API does, and need the owner or someone whose role reaches every address, through an app that reaches every address.
The key list and logs answer for the owner, or someone whose role holds api-keys:read and reaches every address, and the webhook logs and deliveries for the owner or someone whose role reaches every address, in both cases through an app that reaches every address, because a delivery body names the addresses the event is about. replayWebhookDelivery reaches a real receiver, so the assistant in the app always shows a card to approve it and a client should ask first as well. It is refused with retry_in_flight while an automatic retry of the event is being sent and with replay_in_flight while another replay of it is.
Some tools on this server make a change the REST API guards with a verification code, and ask for the same code. Until the client has verified a code in the last 60 minutes, or the person has chosen Allow changes for 60 minutes on it in Account → Connected apps, such a tool answers with a result that starts Refused (step_up_required): and changes nothing. emptyAudience never asks for a code. The API Authentication page lists every tool that asks, and shows how to ask for a code and verify it.
Reference
listApiKeys
Every API key this workspace has issued, what it may do and what it may send as. The secret is shown once, when the key is made or rotated, and nothing recovers it afterwards, so what you get here is a masked form that is enough to tell two keys apart and nothing more. Send scope is the line worth reading: a key with no scope set may send as any address the workspace owns, and a key that names domains or addresses also reads only the sent mail, tracking and calendar of that same set. One page at a time: when more follow, the last line gives a cursor to pass back for the next page.
Inputs
limitinteger- At least 1At most 100
cursorstring
Also available in
- API
GET /keysGET /keys/{id}- TypeScript
nextmail.keys.list()nextmail.keys.listAll()nextmail.keys.iterate()nextmail.keys.get()- Python
keys.list()keys.list_all()keys.iterate()keys.get()- Ruby
keys.listkeys.list_allkeys.iteratekeys.get- PHP
keys->listkeys->listAllkeys->iteratekeys->get- Go
Keys.ListKeys.ListAllKeys.IterateKeys.Get- Java
keys().listkeys().listAllkeys().iteratekeys().get- C#
Keys.ListAsyncKeys.ListAllAsyncKeys.IterateAsyncKeys.GetAsync
listWebhooks
Every webhook endpoint this workspace has, where it posts, whether it is enabled, which events it asked for and which addresses it hears about. An endpoint with no events listed receives every email event except email.replied, and one that names no addresses hears about every address this workspace owns. A delivery is tried up to 8 times over about 27 and a half hours before it is given up on, and a delivery that still failed can be replayed, one event at a time, from Settings or the API. An endpoint whose deliveries have all failed a hundred events in a row is disabled automatically, with the reason and the time shown here. Signing secrets are never shown. One page at a time: when more follow, the last line gives a cursor to pass back for the next page.
Inputs
limitinteger- At least 1At most 100
cursorstring
Also available in
- API
GET /webhooksGET /webhooks/{id}- TypeScript
nextmail.webhooks.list()nextmail.webhooks.listAll()nextmail.webhooks.iterate()nextmail.webhooks.get()- Python
webhooks.list()webhooks.list_all()webhooks.iterate()webhooks.get()- Ruby
webhooks.listwebhooks.list_allwebhooks.iteratewebhooks.get- PHP
webhooks->listwebhooks->listAllwebhooks->iteratewebhooks->get- Go
Webhooks.ListWebhooks.ListAllWebhooks.IterateWebhooks.Get- Java
webhooks().listwebhooks().listAllwebhooks().iteratewebhooks().get- C#
Webhooks.ListAsyncWebhooks.ListAllAsyncWebhooks.IterateAsyncWebhooks.GetAsync
listWebhookEvents
Every event an endpoint in this workspace can subscribe to, with a line saying when each one fires. Events are grouped by family: email events describe one message, domain events describe a domain changing state, and suppression events describe the list of addresses this workspace may no longer send to. An endpoint that names no events receives every email event except email.replied, so email.replied and the domain and suppression families only reach an endpoint that asks for them by name.
Inputs
Takes no input.
Also available in
listApiKeyRequests
The request log of the API keys in this workspace, newest first: every authenticated REST call a key made, with its method, path, status, error code, duration, IP and user agent. Never a body or a query string. Nothing is pruned, so the log reaches back to the first call. Narrow it to one key with keyId, to failed calls (status 400 and up) with failedOnly, to exact status codes with statuses, to one route with path, and to a window with since and until. The filters combine. path matches the route rather than the exact path: ids and addresses in it count as :id and :address, so /emails/:id reads every call to one email, and a path ending in * reads every route that starts with it. Calls made with an OAuth access token are not in it. One page at a time: when more follow, the last line gives a cursor to pass back for the next page.
Inputs
keyIdstring- Not empty
failedOnlybooleanstatusesinteger[]Only calls answered with one of these HTTP status codes, such as [401, 403].
Up to 20 itemspathstringOnly calls to this route, such as /emails or /emails/:id. End it with * to match every route that starts with it, such as /emails/*.
sincestringOnly rows at or after this ISO 8601 instant, such as 2026-09-01T00:00:00Z.
untilstringOnly rows before this ISO 8601 instant.
limitinteger- At least 1At most 100
cursorstring
Also available in
- API
GET /keys/requestsGET /keys/{id}/requests- TypeScript
nextmail.keys.listWorkspaceRequests()nextmail.keys.listAllWorkspaceRequests()nextmail.keys.iterateWorkspaceRequests()nextmail.keys.listRequests()nextmail.keys.listAllRequests()nextmail.keys.iterateRequests()- Python
keys.list_workspace_requests()keys.list_all_workspace_requests()keys.iterate_workspace_requests()keys.list_requests()keys.list_all_requests()keys.iterate_requests()- Ruby
keys.list_workspace_requestskeys.list_all_workspace_requestskeys.iterate_workspace_requestskeys.list_requestskeys.list_all_requestskeys.iterate_requests- PHP
keys->listWorkspaceRequestskeys->listAllWorkspaceRequestskeys->iterateWorkspaceRequestskeys->listRequestskeys->listAllRequestskeys->iterateRequests- Go
Keys.ListWorkspaceRequestsKeys.ListAllWorkspaceRequestsKeys.IterateWorkspaceRequestsKeys.ListRequestsKeys.ListAllRequestsKeys.IterateRequests- Java
keys().listWorkspaceRequestskeys().listAllWorkspaceRequestskeys().iterateWorkspaceRequestskeys().listRequestskeys().listAllRequestskeys().iterateRequests- C#
Keys.ListWorkspaceRequestsAsyncKeys.ListAllWorkspaceRequestsAsyncKeys.IterateWorkspaceRequestsAsyncKeys.ListRequestsAsyncKeys.ListAllRequestsAsyncKeys.IterateRequestsAsync
listApiKeyActivity
What happened TO the API keys in this workspace, newest first: created, updated, rotated, switched off or on, revoked, deleted, and every refused attempt to authenticate with one. Each row says who did it, a person as @username or a key as "API key <name>", and what changed. Narrow it with keyId, since and until. One page at a time: when more follow, the last line gives a cursor to pass back for the next page.
Inputs
keyIdstring- Not empty
sincestringOnly rows at or after this ISO 8601 instant, such as 2026-09-01T00:00:00Z.
untilstringOnly rows before this ISO 8601 instant.
limitinteger- At least 1At most 100
cursorstring
Also available in
- API
GET /keys/activityGET /keys/{id}/activity- TypeScript
nextmail.keys.listWorkspaceActivity()nextmail.keys.listAllWorkspaceActivity()nextmail.keys.iterateWorkspaceActivity()nextmail.keys.listActivity()nextmail.keys.listAllActivity()nextmail.keys.iterateActivity()- Python
keys.list_workspace_activity()keys.list_all_workspace_activity()keys.iterate_workspace_activity()keys.list_activity()keys.list_all_activity()keys.iterate_activity()- Ruby
keys.list_workspace_activitykeys.list_all_workspace_activitykeys.iterate_workspace_activitykeys.list_activitykeys.list_all_activitykeys.iterate_activity- PHP
keys->listWorkspaceActivitykeys->listAllWorkspaceActivitykeys->iterateWorkspaceActivitykeys->listActivitykeys->listAllActivitykeys->iterateActivity- Go
Keys.ListWorkspaceActivityKeys.ListAllWorkspaceActivityKeys.IterateWorkspaceActivityKeys.ListActivityKeys.ListAllActivityKeys.IterateActivity- Java
keys().listWorkspaceActivitykeys().listAllWorkspaceActivitykeys().iterateWorkspaceActivitykeys().listActivitykeys().listAllActivitykeys().iterateActivity- C#
Keys.ListWorkspaceActivityAsyncKeys.ListAllWorkspaceActivityAsyncKeys.IterateWorkspaceActivityAsyncKeys.ListActivityAsyncKeys.ListAllActivityAsyncKeys.IterateActivityAsync
listWebhookDeliveries
The delivery log of this workspace’s webhooks, newest first: one row per POST, with the event, the answer the receiver gave, how long it took, which try it was and when the next automatic retry is due. Nothing is pruned, so it reaches the first delivery. Leave endpointId out to read every endpoint at once. status narrows to delivered or failed, and since and until to a window. The body that was sent is not here; getWebhookDelivery reads it. One page at a time: when more follow, the last line gives a cursor to pass back for the next page.
Inputs
endpointIdstring- Not empty
statusstring- One of
"delivered""failed" sincestringOnly rows at or after this ISO 8601 instant, such as 2026-09-01T00:00:00Z.
untilstringOnly rows before this ISO 8601 instant.
limitinteger- At least 1At most 100
cursorstring
Also available in
- API
GET /webhooks/deliveriesGET /webhooks/{id}/deliveries- TypeScript
nextmail.webhooks.listWorkspaceDeliveries()nextmail.webhooks.listAllWorkspaceDeliveries()nextmail.webhooks.iterateWorkspaceDeliveries()nextmail.webhooks.listDeliveries()nextmail.webhooks.listAllDeliveries()nextmail.webhooks.iterateDeliveries()- Python
webhooks.list_workspace_deliveries()webhooks.list_all_workspace_deliveries()webhooks.iterate_workspace_deliveries()webhooks.list_deliveries()webhooks.list_all_deliveries()webhooks.iterate_deliveries()- Ruby
webhooks.list_workspace_deliverieswebhooks.list_all_workspace_deliverieswebhooks.iterate_workspace_deliverieswebhooks.list_deliverieswebhooks.list_all_deliverieswebhooks.iterate_deliveries- PHP
webhooks->listWorkspaceDeliverieswebhooks->listAllWorkspaceDeliverieswebhooks->iterateWorkspaceDeliverieswebhooks->listDeliverieswebhooks->listAllDeliverieswebhooks->iterateDeliveries- Go
Webhooks.ListWorkspaceDeliveriesWebhooks.ListAllWorkspaceDeliveriesWebhooks.IterateWorkspaceDeliveriesWebhooks.ListDeliveriesWebhooks.ListAllDeliveriesWebhooks.IterateDeliveries- Java
webhooks().listWorkspaceDeliverieswebhooks().listAllWorkspaceDeliverieswebhooks().iterateWorkspaceDeliverieswebhooks().listDeliverieswebhooks().listAllDeliverieswebhooks().iterateDeliveries- C#
Webhooks.ListWorkspaceDeliveriesAsyncWebhooks.ListAllWorkspaceDeliveriesAsyncWebhooks.IterateWorkspaceDeliveriesAsyncWebhooks.ListDeliveriesAsyncWebhooks.ListAllDeliveriesAsyncWebhooks.IterateDeliveriesAsync
getWebhookDelivery
One webhook delivery in full: the exact JSON body that was POSTed, the first 2,000 characters the receiver answered, every try of the same event on that endpoint, when the next automatic retry is due, and whether replayWebhookDelivery would send it again (and if not, why). The body names the addresses the event is about, so only the owner of the workspace, or someone whose role reaches every address, can read it, through an app that reaches every address.
Inputs
deliveryIdstringRequired- 1 to 64 characters
Also available in
replayWebhookDelivery
Send one webhook event again, now, with its original id, type, createdAt and data, and a fresh signature. It reaches a real receiver, so confirm with the person before calling it, every time. One event per call; there is no way to replay everything that failed. It is refused with retry_in_flight while an automatic retry of the same event is being sent, with replay_in_flight while another replay of it is, and when the endpoint is switched off, no longer listens for the event, no longer covers its address, or the delivery has no stored body. Only the owner of the workspace, or someone whose role reaches every address, can replay, through an app that reaches every address.
Inputs
deliveryIdstringRequired- 1 to 64 characters
Also available in
listWebhookActivity
What happened TO this workspace’s webhooks, newest first: created, updated, switched on or off (by a person or automatically after repeated failures), secret rotated, tested, replayed and removed. Each row says who did it, a person as @username or a key as "API key <name>", and what changed. A removed webhook keeps its history. Narrow it with endpointId, since and until. One page at a time: when more follow, the last line gives a cursor to pass back for the next page.
Inputs
endpointIdstring- Not empty
sincestringOnly rows at or after this ISO 8601 instant, such as 2026-09-01T00:00:00Z.
untilstringOnly rows before this ISO 8601 instant.
limitinteger- At least 1At most 100
cursorstring
Also available in
- API
GET /webhooks/activityGET /webhooks/{id}/activity- TypeScript
nextmail.webhooks.listWorkspaceActivity()nextmail.webhooks.listAllWorkspaceActivity()nextmail.webhooks.iterateWorkspaceActivity()nextmail.webhooks.listActivity()nextmail.webhooks.listAllActivity()nextmail.webhooks.iterateActivity()- Python
webhooks.list_workspace_activity()webhooks.list_all_workspace_activity()webhooks.iterate_workspace_activity()webhooks.list_activity()webhooks.list_all_activity()webhooks.iterate_activity()- Ruby
webhooks.list_workspace_activitywebhooks.list_all_workspace_activitywebhooks.iterate_workspace_activitywebhooks.list_activitywebhooks.list_all_activitywebhooks.iterate_activity- PHP
webhooks->listWorkspaceActivitywebhooks->listAllWorkspaceActivitywebhooks->iterateWorkspaceActivitywebhooks->listActivitywebhooks->listAllActivitywebhooks->iterateActivity- Go
Webhooks.ListWorkspaceActivityWebhooks.ListAllWorkspaceActivityWebhooks.IterateWorkspaceActivityWebhooks.ListActivityWebhooks.ListAllActivityWebhooks.IterateActivity- Java
webhooks().listWorkspaceActivitywebhooks().listAllWorkspaceActivitywebhooks().iterateWorkspaceActivitywebhooks().listActivitywebhooks().listAllActivitywebhooks().iterateActivity- C#
Webhooks.ListWorkspaceActivityAsyncWebhooks.ListAllWorkspaceActivityAsyncWebhooks.IterateWorkspaceActivityAsyncWebhooks.ListActivityAsyncWebhooks.ListAllActivityAsyncWebhooks.IterateActivityAsync
getWebhook
One webhook endpoint: where it posts, whether it is on and why not, which events it asked for, which addresses it hears about, and when it last delivered. The signing secret is never shown.
Inputs
idstringRequiredThe webhook endpoint, by its id (whe_…). listWebhooks names every one.
1 to 64 characters
Also available in
- API
GET /webhooksGET /webhooks/{id}- TypeScript
nextmail.webhooks.list()nextmail.webhooks.listAll()nextmail.webhooks.iterate()nextmail.webhooks.get()- Python
webhooks.list()webhooks.list_all()webhooks.iterate()webhooks.get()- Ruby
webhooks.listwebhooks.list_allwebhooks.iteratewebhooks.get- PHP
webhooks->listwebhooks->listAllwebhooks->iteratewebhooks->get- Go
Webhooks.ListWebhooks.ListAllWebhooks.IterateWebhooks.Get- Java
webhooks().listwebhooks().listAllwebhooks().iteratewebhooks().get- C#
Webhooks.ListAsyncWebhooks.ListAllAsyncWebhooks.IterateAsyncWebhooks.GetAsync
createWebhook
Add a webhook endpoint: an https URL that Nextmail posts signed events to. Name the events it wants, from listWebhookEvents; with none it gets every email event except email.replied. Allowlists narrow it to some addresses or domains. The answer holds the signing secret, shown this once.
- Asks for a verification code
POST /webhooks
Inputs
urlstringRequired- 1 to 2048 characters
eventTypesstring[]- Up to 51 itemsOne of
"email.received""email.replied""email.sent""email.failed""email.cancelled""email.scheduled""email.queued""email.delivered""email.delivery_delayed""email.bounced""email.complained""email.suppressed""email.opened""email.clicked""email.downloaded""domain.verified""domain.sending_changed""domain.deleted""suppression.added""suppression.removed""file.uploaded""file.deleted""form.submitted""form.confirmed""automation.entered""automation.exited""automation.paused""automation.resumed""automation.webhook""contact.created""contact.updated""contact.deleted""contact.unsubscribed""contact.resubscribed""sending.paused""sending.resumed""connector.connected""connector.disconnected""connector.needs_attention""task.run.completed""task.run.failed""task.run.cancelled""approval.requested""booking.created""booking.confirmed""booking.rescheduled""booking.cancelled""broadcast.sending""broadcast.sent""broadcast.failed""broadcast.cancelled" descriptionstring- Up to 200 characters
addressAllowliststring[]Only events about these addresses. What you pass replaces the list.
Up to 50 itemsdomainAllowliststring[]Only events about addresses on these domains. What you pass replaces the list.
Up to 25 items
Also available in
updateWebhook
Change a webhook endpoint: its URL, the events it wants, its description, its allowlists, or switch it on or off with enabled. Switching on clears an automatic disable. Lists you pass replace what it had.
- Asks for a verification code
PATCH /webhooks/{id}
Inputs
idstringRequiredThe webhook endpoint, by its id (whe_…). listWebhooks names every one.
1 to 64 charactersurlstring- 1 to 2048 characters
eventTypesstring[]- Up to 51 itemsOne of
"email.received""email.replied""email.sent""email.failed""email.cancelled""email.scheduled""email.queued""email.delivered""email.delivery_delayed""email.bounced""email.complained""email.suppressed""email.opened""email.clicked""email.downloaded""domain.verified""domain.sending_changed""domain.deleted""suppression.added""suppression.removed""file.uploaded""file.deleted""form.submitted""form.confirmed""automation.entered""automation.exited""automation.paused""automation.resumed""automation.webhook""contact.created""contact.updated""contact.deleted""contact.unsubscribed""contact.resubscribed""sending.paused""sending.resumed""connector.connected""connector.disconnected""connector.needs_attention""task.run.completed""task.run.failed""task.run.cancelled""approval.requested""booking.created""booking.confirmed""booking.rescheduled""booking.cancelled""broadcast.sending""broadcast.sent""broadcast.failed""broadcast.cancelled" descriptionstring- Can be nullUp to 200 characters
enabledbooleanaddressAllowliststring[]Only events about these addresses. What you pass replaces the list.
Up to 50 itemsdomainAllowliststring[]Only events about addresses on these domains. What you pass replaces the list.
Up to 25 items
Also available in
deleteWebhook
Remove a webhook endpoint. Nothing is posted to it from then on, and its delivery log and history stay readable. updateWebhook with enabled false is the reversible way to stop one.
Inputs
idstringRequiredThe webhook endpoint, by its id (whe_…). listWebhooks names every one.
1 to 64 characters
Also available in
rotateWebhookSecret
Give a webhook endpoint a new signing secret. For 24 hours every delivery is signed with the old secret as well, so the receiver keeps verifying while it is given the new one. The new secret is shown once, in the answer to this call.
Inputs
idstringRequiredThe webhook endpoint, by its id (whe_…). listWebhooks names every one.
1 to 64 characters
Also available in
testWebhook
Post one signed test event to a webhook endpoint now and report what it answered. It reaches the real receiver, and it is recorded in the activity of the endpoint.
Inputs
idstringRequiredThe webhook endpoint, by its id (whe_…). listWebhooks names every one.
1 to 64 characters
Also available in
- API
POST /webhooks/{id}/test- TypeScript
nextmail.webhooks.test()- Python
webhooks.test()- Ruby
webhooks.test- PHP
webhooks->test- Go
Webhooks.Test- Java
webhooks().test- C#
Webhooks.TestAsync
getWebhookStats
How the webhook deliveries went inside a window: attempts, delivered and failed, the median time a receiver took, a count per bucket of grain, the events sent most and the response codes. Every endpoint, or the ones endpointIds names. The window is the last 30 days unless since or until say otherwise.
Inputs
endpointIdsstring[]- Up to 50 items
sincestringAn ISO 8601 instant, such as 2026-09-01T00:00:00Z.
untilstringAn ISO 8601 instant, such as 2026-09-01T00:00:00Z.
grainstring- One of
"minute""hour""day" offsetMinutesinteger- At least -840At most 840
Also available in
getApiKeyStats
What the API keys of this workspace did inside a window, as the Analytics tab of the API keys page shows it: the mail they sent and what became of it, the calls refused for a bad secret, the requests made and how many failed, the routes called most and the status codes returned. Every key, or the ones keyIds names. The window is the last 30 days unless since or until say otherwise. Only the owner of the workspace can read it.
Inputs
keyIdsstring[]- Up to 50 items
sincestringAn ISO 8601 instant, such as 2026-09-01T00:00:00Z.
untilstringAn ISO 8601 instant, such as 2026-09-01T00:00:00Z.
grainstring- One of
"minute""hour""day" offsetMinutesinteger- At least -840At most 840
Also available in
- API
GET /keys/stats- TypeScript
nextmail.keys.stats()- Python
keys.stats()- Ruby
keys.stats- PHP
keys->stats- Go
Keys.Stats- Java
keys().stats- C#
Keys.StatsAsync