Skip to the documentation
API

Account

Every operation in this group: what it accepts, what it returns and the errors it can answer with.

Operations

What this key is and may do.

GET/addresses

What this key may send as

Scopesemails:sendReads

The answer to an unexplained 403 or 409. unrestricted is true only on a key with neither allowlist set, and it means any local-part on a verified domain is accepted, including ones nobody has created. A key holding whole domains reads as unrestricted: false and still takes any local-part on those domains, so GET /keys/self is where you read which ones. canSend on an address is false when the address is disabled, when neither allowlist on the key covers it, or when the domain cannot sign yet, and sendingVerified on each domain is that last fact on its own.

Requires the emails:send scope.

Query parameters

limitinteger

Rows per page, 1 to 100.

At least 1At most 100Default25
cursorstring

The previous page's nextCursor, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400 invalid_cursor.

Returns

A page of addresses, alphabetically, with hasMore and nextCursor, plus unrestricted and every sendable domain on each page.

Errors

The errors every operation can return400401403404422429500Error catalog

Also available in

TypeScript
nextmail.addresses.list()nextmail.addresses.listAll()nextmail.addresses.iterate()
Python
addresses.list()addresses.list_all()addresses.iterate()
Ruby
addresses.listaddresses.list_alladdresses.iterate
PHP
addresses->listaddresses->listAlladdresses->iterate
Go
Addresses.ListAddresses.ListAllAddresses.Iterate
Java
addresses().listaddresses().listAlladdresses().iterate
C#
Addresses.ListAsyncAddresses.ListAllAsyncAddresses.IterateAsync
CLI
nextmail addresses list
MCP
whoAmI

GET/keys/self

What this key is

No scopeReads

Needs no scope: a key may always describe itself.

scopes is the EFFECTIVE list and the only one that authorises anything: the scopes on the key itself, intersected with the permissions of the role it was issued under. grantedScopes is what the key was created holding, and roleId names the ceiling that narrowed it, so anything in the first list and missing from the second was removed by that role.

That difference is the answer to the confusing 403. A key created with emails:send and capped by a viewer role is refused for lacking emails:send, which reads as a lie against the key the console is displaying; the fix is to change the role rather than to mint another key. roleId is null on a key with no ceiling, which is what every key issued before roles existed still has.

Two independent lists narrow what the key may send as. domainAllowlist holds whole domains, and the key may send as any address on one of them, including addresses created after the key was. addressAllowlist holds individual addresses. Both null or both empty means the key may send as any address the workspace owns. With either one set the key is narrowed, and reads of sent mail, tracking and calendar narrow to the same set. An address whose domain is already in domainAllowlist is dropped from addressAllowlist when the lists are written, so the two never overlap.

Returns

Id, mode, effective scopes, the role capping them, and both allowlists.

Errors

The errors every operation can return400401403404422429500Error catalog

Also available in

TypeScript
nextmail.me.get()
Python
me.get()
Ruby
me.get
PHP
me->get
Go
Me.Get
Java
me().get
C#
Me.GetAsync
CLI
nextmail me get
MCP
whoAmI

POST/keys/self/rotate

Replace this key's secret

Scopeskeys:writeDeletes

Mints a new secret for the key making the call and returns it once. There is no body and no way to name another key here: this call rotates the caller and nothing else, and POST /keys/{id}/rotate is the one that reaches other keys, behind keys:manage.

The old secret stops working the instant this returns. There is no overlap window and no grace period, and the response is the only place the new secret ever appears, so a caller that drops it has locked itself out until somebody in the console rotates the key again.

Everything else about the key is unchanged: same id, same name, same mode, same scopes, same role, same allowlists and same expiry. Only the last four characters move, because they are part of the secret. The request history hangs off the id rather than off the secret, so it runs straight through a rotation and reads as one key on both sides of it rather than as two.

Weigh that before granting keys:write. A stolen key holding it can rotate itself and take the secret away from the person who owns the key. It cannot hide while doing so, because the id does not move and revoking it from the console still works.

Requires the keys:write scope.

Returns

The body of GET /keys/self, plus token, the new secret in full and for the only time, rotationCount, an integer counting every rotation this key has had, and rotatedAt, when this one landed, ISO-8601.

Errors

403

insufficient_scope: the key lacks keys:write. api_key_only: the request carried an OAuth access token, which has no secret to rotate.

404

resource_not_found: the key is gone. It authenticated this request and was deleted before the rotation landed, which is the only way to reach this.

409

revoked: the key was revoked between authenticating this request and rotating it. expired: it passed its expiry in the same gap. Neither is rotatable, and a key in either state authenticates nothing afterwards, so the answer is a new key from the console.

The errors every operation can return400401422429500Error catalog

Also available in

TypeScript
nextmail.me.rotate()
Python
me.rotate()
Ruby
me.rotate
PHP
me->rotate
Go
Me.Rotate
Java
me().rotate
C#
Me.RotateAsync
CLI
nextmail me rotate

GET/keys/self/requests

List this key's requests

No scopeReads

The request log of the key making the call, newest first: every authenticated call it made, with method, path, status, error code, duration, IP and user agent, never a body or a query string. Needs no scope: a key may always read its own log, and it reads no other key's here. GET /keys/{id}/requests and GET /keys/requests are the ones that reach other keys, behind keys:read.

failedOnly, status, path, since and until narrow it, and they combine. Nothing is pruned, so the log reaches back to the key's first call, and it runs straight through a rotation because it hangs off the key id. The call that reads the log is logged too.

Query parameters

failedOnlyboolean

Only calls answered with a status of 400 or more.

Defaultfalse
statusstring

Only calls answered with one of these HTTP status codes, comma-separated, such as 401,403. At most 20 codes, each from 100 to 599. Anything else is a 422 invalid_parameter.

pathstring

Only calls to this route, whatever the method, such as /emails or /emails/:id. The log matches the route, not the exact path: an id in the path counts as :id and an email address as :address, so /emails/4c1b257a66287fd113bd89d0 reads every call to /emails/:id. End it with * to read every route that starts with it, such as /emails/*. It takes no query string, and a value that is not a path is a 422 invalid_parameter.

sincestring

Only rows at or after this instant, ISO 8601. One that does not parse is a 400 invalid_parameter.

Formatdate-time
untilstring

Only rows before this instant. It has to be later than since.

Formatdate-time
limitinteger

Rows per page, 1 to 100.

At least 1At most 100Default25
cursorstring

The previous page's nextCursor, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400 invalid_cursor.

Returns

A page of calls, newest first.

Errors

403

api_key_only: the request carried an OAuth access token. Calls made with one are not logged, so there is nothing to read.

The errors every operation can return400401404422429500Error catalog

Also available in

TypeScript
nextmail.me.listRequests()nextmail.me.listAllRequests()nextmail.me.iterateRequests()
Python
me.list_requests()me.list_all_requests()me.iterate_requests()
Ruby
me.list_requestsme.list_all_requestsme.iterate_requests
PHP
me->listRequestsme->listAllRequestsme->iterateRequests
Go
Me.ListRequestsMe.ListAllRequestsMe.IterateRequests
Java
me().listRequestsme().listAllRequestsme().iterateRequests
C#
Me.ListRequestsAsyncMe.ListAllRequestsAsyncMe.IterateRequestsAsync
CLI
nextmail me list-requests

GET/keys/self/activity

List this key's activity

No scopeReads

What happened to the key making the call, newest first: created, updated, rotated, deactivated, reactivated, and every attempt to authenticate with it that was refused. actor says who, a person as @username or a key as API key <name>, and detail.source where from. Needs no scope, and it reads no other key's history: GET /keys/{id}/activity and GET /keys/activity do that, behind keys:read. since and until narrow it.

Query parameters

sincestring

Only rows at or after this instant, ISO 8601. One that does not parse is a 400 invalid_parameter.

Formatdate-time
untilstring

Only rows before this instant. It has to be later than since.

Formatdate-time
limitinteger

Rows per page, 1 to 100.

At least 1At most 100Default25
cursorstring

The previous page's nextCursor, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400 invalid_cursor.

Returns

A page of changes, newest first.

Errors

403

api_key_only: the request carried an OAuth access token, which is not a key and has no key history.

The errors every operation can return400401404422429500Error catalog

Also available in

TypeScript
nextmail.me.listActivity()nextmail.me.listAllActivity()nextmail.me.iterateActivity()
Python
me.list_activity()me.list_all_activity()me.iterate_activity()
Ruby
me.list_activityme.list_all_activityme.iterate_activity
PHP
me->listActivityme->listAllActivityme->iterateActivity
Go
Me.ListActivityMe.ListAllActivityMe.IterateActivity
Java
me().listActivityme().listAllActivityme().iterateActivity
C#
Me.ListActivityAsyncMe.ListAllActivityAsyncMe.IterateActivityAsync
CLI
nextmail me list-activity

GET/keys/self/stats

Read this key's stats

No scopeReads

What the key making the call did inside a window: the requests it made and how many failed, the calls refused because its secret was wrong, revoked or expired, the 8 routes it called most with the median time each took, and the status codes it got back. Needs no scope: a key may always read its own figures, and it reads no other key's here. GET /keys/stats is the one that reaches other keys.

sends, the mail the key sent and what became of it, is filled only when the key holds emails:read. Without that scope it is null, never zeros, so a missing permission cannot read as a quiet week.

Query parameters

sincestring

The start of the window, an ISO 8601 instant. Left out, 30 days before until.

Formatdate-time
untilstring

The end of the window, an ISO 8601 instant, not included. Left out, now.

Formatdate-time
grainstring

How wide one bucket of the series is. The bucket keys change shape with it: YYYY-MM-DD for a day, YYYY-MM-DDTHH for an hour, YYYY-MM-DDTHH:MM for a minute.

One of"minute""hour""day"Default"day"
offsetMinutesinteger

Minutes to add to UTC before cutting the buckets, so a day starts at midnight where the reader is. 120 for UTC+2.

At least -840At most 840Default0

Returns

The figures for the window.

Errors

403

api_key_only: the request carried an OAuth access token. Calls made with one are not logged, so there are no figures to read.

The errors every operation can return400401404422429500Error catalog

Also available in

TypeScript
nextmail.me.stats()
Python
me.stats()
Ruby
me.stats
PHP
me->stats
Go
Me.Stats
Java
me().stats
C#
Me.StatsAsync
CLI
nextmail me stats

Objects

ApiKeyActivityEntryobject

objectstring
One of"api_key_event"
idstring
keyIdstring
keyNamestring

Deleted key once the key itself is gone.

typestring
One of"created""updated""rotated""revoked""deactivated""reactivated""auth_failed""deleted"
createdAtstring
Formatdate-time
detailobject

What changed and where it was changed from (source: console, api, mcp or documentation). A refused authentication carries reason, and via: smtp when it was an SMTP sign-in.

ApiKeyActivityListobject

objectstring
One of"list"
hasMoreboolean

True when another page follows. Pass nextCursor back as cursor to read it.

nextCursorstring

An opaque cursor for the next page, or null on the last page. Pass it back unchanged.

Can be null

ApiKeyRequestobject

One authenticated call a key made, or one message it handed over SMTP. Never a body or a query string.

objectstring
One of"api_key_request"
idstring
keyIdstring
keyNamestring

Deleted key once the key itself is gone.

requestIdstring

The X-Request-Id the call was answered with.

Can be null
methodstring

The HTTP method, or SMTP for a message the key handed over SMTP.

pathstring

The path that was called. A message handed over SMTP is logged as /emails.

statusinteger

The HTTP status. A message handed over SMTP carries the status the same send would have had over REST.

errorCodestring
Can be null
durationMsinteger
ipstring
Can be null
userAgentstring

smtp for a message handed over SMTP.

Can be null
createdAtstring
Formatdate-time

ApiKeyRequestListobject

objectstring
One of"list"
hasMoreboolean

True when another page follows. Pass nextCursor back as cursor to read it.

nextCursorstring

An opaque cursor for the next page, or null on the last page. Pass it back unchanged.

Can be null

AuditActorobject

Who made the change: a person, or a key acting over the API. Null when Nextmail made it on its own, such as switching a webhook off after 100 failed events in a row, and when the person or key has since been deleted.

Can be null
kindstring
One of"user""apiKey"
idstring

The account id of the person, or the id of the key.

namestring

The name of the person, or API key <name> for a key.

usernamestring
Can be null
labelstring

What the app shows: @username for a person who has a username, otherwise name.

KeySelfobject

objectstringRequired
One of"api_key""oauth_token"
kindstringRequired
One of"apiKey""oauth"
idstringRequired

The key id. Null for an access token.

Can be null
clientIdstring

The app the access token belongs to. Only on an access token.

modestringRequired
One of"live""test"
scopesstring[]Required

What this credential may do now: its own scopes held to the role it acts under.

One of"emails:send""emails:read""drafts:read""drafts:write""threads:read""threads:write""files:read""files:write""labels:read""labels:write""contacts:read""contacts:write""audiences:read""audiences:write""calendar:read""calendar:write""templates:read""templates:write""domains:read""domains:write""webhooks:read""webhooks:write""rules:read""rules:write""connections:read""members:read""members:write""roles:read""roles:write""settings:read""settings:write""keys:write""keys:read""keys:manage""forms:read""forms:write""knowledge:read""knowledge:write""automations:read""automations:write""tasks:read""tasks:write""connectors:read""connectors:use""connectors:write""billing:read""billing:write""account:read""account:write"
roleIdstringRequired

The role the credential acts under. Null for none.

Can be null
grantedScopesstring[]Required

The scopes it was given, before the role narrows them.

One of"emails:send""emails:read""drafts:read""drafts:write""threads:read""threads:write""files:read""files:write""labels:read""labels:write""contacts:read""contacts:write""audiences:read""audiences:write""calendar:read""calendar:write""templates:read""templates:write""domains:read""domains:write""webhooks:read""webhooks:write""rules:read""rules:write""connections:read""members:read""members:write""roles:read""roles:write""settings:read""settings:write""keys:write""keys:read""keys:manage""forms:read""forms:write""knowledge:read""knowledge:write""automations:read""automations:write""tasks:read""tasks:write""connectors:read""connectors:use""connectors:write""billing:read""billing:write""account:read""account:write"
workspaceIdstringRequired
addressAllowliststring[]Required

The single addresses it is limited to. Null when it is not limited to any.

Can be null
domainAllowliststring[]Required

The domains it is limited to. Null when it is not limited to any.

Can be null
expiresAtstring

When the approval behind the access token ends. Only on an access token.

Can be nullFormatdate-time

KeySelfStatsobject

objectstringRequired
One of"api_key_stats"
sincestringRequired
Formatdate-time
untilstringRequired
Formatdate-time
grainstringRequired
One of"minute""hour""day"
keyIdsstring[]Required

The id of the key making the call, and nothing else.

sendsobjectRequired

The mail the key sent, with what became of it. null when the key does not hold emails:read, never zeros.

Can be null
daysobject[]
daystring

The bucket, shaped by grain.

sentinteger
deliveredinteger
failedinteger
bouncedinteger
complainedinteger
totalsobject
sendsinteger
testSendsinteger
recipientsinteger
deliveredinteger
failedinteger
bouncedinteger
complainedinteger
uncertaininteger
pendinginteger
statusesobject[]

Sends by status.

labelstring
countinteger
sourcesobject[]

Sends by where they came from.

labelstring
countinteger
sendersobject[]

Sends by the address they went out as.

labelstring
countinteger
suppressedobject[]

Recipients skipped because they were suppressed, by reason.

labelstring
countinteger
rejectedobject[]Required

Calls refused because the secret was wrong, revoked or expired, per bucket.

bucketstring
countinteger
requestsobject[]Required

Requests made and how many of them failed with a 4xx or 5xx, per bucket.

bucketstring
countinteger
failedinteger
routesobject[]Required

The routes called most, with how many failed and the median time in milliseconds.

labelstring
countinteger
failedinteger
medianMsinteger
codesobject[]Required

Requests by the HTTP status they got back.

labelstring
countinteger

Pingobject

okbooleanRequired
One oftrue
kindstringRequired
One of"apiKey""oauth"
keyIdstringRequired

The key id. Null for an access token.

Can be null
clientIdstring

The app the access token belongs to. Only on an access token.

modestringRequired
One of"live""test"
scopesstring[]Required

What this credential may do now: its own scopes held to the role it acts under.

One of"emails:send""emails:read""drafts:read""drafts:write""threads:read""threads:write""files:read""files:write""labels:read""labels:write""contacts:read""contacts:write""audiences:read""audiences:write""calendar:read""calendar:write""templates:read""templates:write""domains:read""domains:write""webhooks:read""webhooks:write""rules:read""rules:write""connections:read""members:read""members:write""roles:read""roles:write""settings:read""settings:write""keys:write""keys:read""keys:manage""forms:read""forms:write""knowledge:read""knowledge:write""automations:read""automations:write""tasks:read""tasks:write""connectors:read""connectors:use""connectors:write""billing:read""billing:write""account:read""account:write"
roleIdstringRequired

The role the credential acts under. Null for none.

Can be null
grantedScopesstring[]Required

The scopes it was given, before the role narrows them.

One of"emails:send""emails:read""drafts:read""drafts:write""threads:read""threads:write""files:read""files:write""labels:read""labels:write""contacts:read""contacts:write""audiences:read""audiences:write""calendar:read""calendar:write""templates:read""templates:write""domains:read""domains:write""webhooks:read""webhooks:write""rules:read""rules:write""connections:read""members:read""members:write""roles:read""roles:write""settings:read""settings:write""keys:write""keys:read""keys:manage""forms:read""forms:write""knowledge:read""knowledge:write""automations:read""automations:write""tasks:read""tasks:write""connectors:read""connectors:use""connectors:write""billing:read""billing:write""account:read""account:write"
workspaceIdstringRequired

RotatedKeySelfobject

objectstringRequired
One of"api_key"
idstringRequired
modestringRequired
One of"live""test"
scopesstring[]Required

What this credential may do now: its own scopes held to the role it acts under.

One of"emails:send""emails:read""drafts:read""drafts:write""threads:read""threads:write""files:read""files:write""labels:read""labels:write""contacts:read""contacts:write""audiences:read""audiences:write""calendar:read""calendar:write""templates:read""templates:write""domains:read""domains:write""webhooks:read""webhooks:write""rules:read""rules:write""connections:read""members:read""members:write""roles:read""roles:write""settings:read""settings:write""keys:write""keys:read""keys:manage""forms:read""forms:write""knowledge:read""knowledge:write""automations:read""automations:write""tasks:read""tasks:write""connectors:read""connectors:use""connectors:write""billing:read""billing:write""account:read""account:write"
roleIdstringRequired

The role the credential acts under. Null for none.

Can be null
grantedScopesstring[]Required

The scopes it was given, before the role narrows them.

One of"emails:send""emails:read""drafts:read""drafts:write""threads:read""threads:write""files:read""files:write""labels:read""labels:write""contacts:read""contacts:write""audiences:read""audiences:write""calendar:read""calendar:write""templates:read""templates:write""domains:read""domains:write""webhooks:read""webhooks:write""rules:read""rules:write""connections:read""members:read""members:write""roles:read""roles:write""settings:read""settings:write""keys:write""keys:read""keys:manage""forms:read""forms:write""knowledge:read""knowledge:write""automations:read""automations:write""tasks:read""tasks:write""connectors:read""connectors:use""connectors:write""billing:read""billing:write""account:read""account:write"
workspaceIdstringRequired
addressAllowliststring[]Required

The single addresses it is limited to. Null when it is not limited to any.

Can be null
domainAllowliststring[]Required

The domains it is limited to. Null when it is not limited to any.

Can be null
tokenstringRequired

The new secret, shown this once. The old one stops working now.

rotationCountintegerRequired
At least 1
rotatedAtstringRequired
Formatdate-time

SendableAddressobject

objectstringRequired
One of"address"
addressstringRequired
Formatemail
enabledbooleanRequired
canSendbooleanRequired

SendableAddressListobject

objectstring
One of"list"
hasMoreboolean

True when another page follows. Pass nextCursor back as cursor to read it.

nextCursorstring

An opaque cursor for the next page, or null on the last page. Pass it back unchanged.

Can be null
unrestrictedboolean

True only on a key with neither allowlist set: any local-part on a verified domain is accepted.

SendableDomainobject

domainstringRequired
receivingVerifiedbooleanRequired
sendingVerifiedbooleanRequired
catchAllbooleanRequired