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
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
limitintegerRows per page, 1 to 100.
At least 1At most 100Default25cursorstringThe 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 400invalid_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
openemail addresses list- MCP
whoAmI
GET/keys/self
What this key is
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
openemail me get- MCP
whoAmI
POST/keys/self/rotate
Replace this key's secret
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 lackskeys: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.
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
openemail me rotate
GET/keys/self/requests
List this key's requests
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
failedOnlybooleanOnly calls answered with a status of 400 or more.
DefaultfalsestatusstringOnly 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 422invalid_parameter.pathstringOnly calls to this route, whatever the method, such as
/emailsor/emails/:id. The log matches the route, not the exact path: an id in the path counts as:idand an email address as:address, so/emails/4c1b257a66287fd113bd89d0reads 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 422invalid_parameter.sincestringOnly rows at or after this instant, ISO 8601. One that does not parse is a 400
invalid_parameter.Formatdate-timeuntilstringOnly rows before this instant. It has to be later than
since.Formatdate-timelimitintegerRows per page, 1 to 100.
At least 1At most 100Default25cursorstringThe 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 400invalid_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
openemail me list-requests
GET/keys/self/activity
List this key's activity
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
sincestringOnly rows at or after this instant, ISO 8601. One that does not parse is a 400
invalid_parameter.Formatdate-timeuntilstringOnly rows before this instant. It has to be later than
since.Formatdate-timelimitintegerRows per page, 1 to 100.
At least 1At most 100Default25cursorstringThe 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 400invalid_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
openemail me list-activity
GET/ping
Auth smoke test
Returns
ok, with the effective scopes and the role that capped them.
Errors
The errors every operation can return400401403404422429500Error catalog
Also available in
- TypeScript
nextmail.me.ping()- Python
me.ping()- Ruby
me.ping- PHP
me->ping- Go
Me.Ping- Java
me().ping- C#
Me.PingAsync- CLI
openemail me ping
GET/keys/self/stats
Read this key's stats
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
sincestringThe start of the window, an ISO 8601 instant. Left out, 30 days before
until.Formatdate-timeuntilstringThe end of the window, an ISO 8601 instant, not included. Left out, now.
Formatdate-timegrainstringHow wide one bucket of the series is. The bucket keys change shape with it:
YYYY-MM-DDfor a day,YYYY-MM-DDTHHfor an hour,YYYY-MM-DDTHH:MMfor a minute.One of"minute""hour""day"Default"day"offsetMinutesintegerMinutes 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
openemail me stats
Objects
ApiKeyActivityEntryobject
objectstring- One of
"api_key_event" idstringkeyIdstringkeyNamestringDeleted keyonce the key itself is gone.typestring- One of
"created""updated""rotated""revoked""deactivated""reactivated""auth_failed""deleted" createdAtstring- Format
date-time actorAuditActordetailobjectWhat changed and where it was changed from (
source: console, api, mcp or documentation). A refused authentication carriesreason, andvia: smtpwhen it was an SMTP sign-in.
ApiKeyActivityListobject
objectstring- One of
"list" hasMorebooleanTrue when another page follows. Pass
nextCursorback ascursorto read it.nextCursorstringAn 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" idstringkeyIdstringkeyNamestringDeleted keyonce the key itself is gone.requestIdstringThe
X-Request-Idthe call was answered with.Can be nullmethodstringThe HTTP method, or
SMTPfor a message the key handed over SMTP.pathstringThe path that was called. A message handed over SMTP is logged as
/emails.statusintegerThe HTTP status. A message handed over SMTP carries the status the same send would have had over REST.
errorCodestring- Can be null
durationMsintegeripstring- Can be null
userAgentstringsmtpfor a message handed over SMTP.Can be nullcreatedAtstring- Format
date-time
ApiKeyRequestListobject
objectstring- One of
"list" dataApiKeyRequest[]hasMorebooleanTrue when another page follows. Pass
nextCursorback ascursorto read it.nextCursorstringAn 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.
kindstring- One of
"user""apiKey" idstringThe account id of the person, or the id of the key.
namestringThe name of the person, or
API key <name>for a key.usernamestring- Can be null
labelstringWhat the app shows:
@usernamefor a person who has a username, otherwisename.
KeySelfobject
objectstringRequired- One of
"api_key""oauth_token" kindstringRequired- One of
"apiKey""oauth" idstringRequiredThe key id. Null for an access token.
Can be nullclientIdstringThe app the access token belongs to. Only on an access token.
modestringRequired- One of
"live""test" scopesstring[]RequiredWhat 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"roleIdstringRequiredThe role the credential acts under. Null for none.
Can be nullgrantedScopesstring[]RequiredThe 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"workspaceIdstringRequiredaddressAllowliststring[]RequiredThe single addresses it is limited to. Null when it is not limited to any.
Can be nulldomainAllowliststring[]RequiredThe domains it is limited to. Null when it is not limited to any.
Can be nullexpiresAtstringWhen the approval behind the access token ends. Only on an access token.
Can be nullFormatdate-time
KeySelfStatsobject
objectstringRequired- One of
"api_key_stats" sincestringRequired- Format
date-time untilstringRequired- Format
date-time grainstringRequired- One of
"minute""hour""day" keyIdsstring[]RequiredThe id of the key making the call, and nothing else.
sendsobjectRequiredThe mail the key sent, with what became of it.
nullwhen the key does not holdemails:read, never zeros.Can be nulldaysobject[]daystringThe bucket, shaped by
grain.sentintegerdeliveredintegerfailedintegerbouncedintegercomplainedinteger
totalsobjectsendsintegertestSendsintegerrecipientsintegerdeliveredintegerfailedintegerbouncedintegercomplainedintegeruncertainintegerpendinginteger
statusesobject[]Sends by status.
labelstringcountinteger
sourcesobject[]Sends by where they came from.
labelstringcountinteger
sendersobject[]Sends by the address they went out as.
labelstringcountinteger
suppressedobject[]Recipients skipped because they were suppressed, by reason.
labelstringcountinteger
rejectedobject[]RequiredCalls refused because the secret was wrong, revoked or expired, per bucket.
bucketstringcountinteger
requestsobject[]RequiredRequests made and how many of them failed with a 4xx or 5xx, per bucket.
bucketstringcountintegerfailedinteger
routesobject[]RequiredThe routes called most, with how many failed and the median time in milliseconds.
labelstringcountintegerfailedintegermedianMsinteger
codesobject[]RequiredRequests by the HTTP status they got back.
labelstringcountinteger
Pingobject
okbooleanRequired- One of
true kindstringRequired- One of
"apiKey""oauth" keyIdstringRequiredThe key id. Null for an access token.
Can be nullclientIdstringThe app the access token belongs to. Only on an access token.
modestringRequired- One of
"live""test" scopesstring[]RequiredWhat 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"roleIdstringRequiredThe role the credential acts under. Null for none.
Can be nullgrantedScopesstring[]RequiredThe 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" idstringRequiredmodestringRequired- One of
"live""test" scopesstring[]RequiredWhat 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"roleIdstringRequiredThe role the credential acts under. Null for none.
Can be nullgrantedScopesstring[]RequiredThe 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"workspaceIdstringRequiredaddressAllowliststring[]RequiredThe single addresses it is limited to. Null when it is not limited to any.
Can be nulldomainAllowliststring[]RequiredThe domains it is limited to. Null when it is not limited to any.
Can be nulltokenstringRequiredThe new secret, shown this once. The old one stops working now.
rotationCountintegerRequired- At least 1
rotatedAtstringRequired- Format
date-time
SendableAddressobject
objectstringRequired- One of
"address" addressstringRequired- Format
email enabledbooleanRequiredcanSendbooleanRequired
SendableAddressListobject
objectstring- One of
"list" hasMorebooleanTrue when another page follows. Pass
nextCursorback ascursorto read it.nextCursorstringAn opaque cursor for the next page, or null on the last page. Pass it back unchanged.
Can be nullunrestrictedbooleanTrue only on a key with neither allowlist set: any local-part on a verified domain is accepted.
domainsSendableDomain[]
SendableDomainobject
domainstringRequiredreceivingVerifiedbooleanRequiredsendingVerifiedbooleanRequiredcatchAllbooleanRequired