otp, magic_link, or other — with the code or link extracted, so an agent can wait for exactly the verification email it needs instead of parsing mail itself.
Most of the time you don’t need this API at all: during a register or login run, Sente reads the verification email and types the code itself. Use these endpoints when your own code drives the flow, or when you want to see what actually arrived.
The message object
Annotation runs immediately after the message is persisted, before the
message.received webhook fires — but a message you read through GET /v1/messages microseconds after arrival can still show annotation: null. Filtering by kind sidesteps this entirely: an unannotated message simply doesn’t match, so wait?kind=otp never returns a message whose code hasn’t been extracted yet.Wait for a verification code
GET /v1/messages/wait
Holds the HTTP request open until a matching message arrives, then returns it. This is the primitive behind “wait for the OTP”.
Returns
200 with the oldest matching message, or 204 with no body when the timeout elapses with nothing matching. On 204, call again with the same since so nothing is skipped.
200 — a message object; the code is at annotation.code, a magic link at annotation.link:
List messages
GET /v1/messages
200: an array of message objects, newest first. Every row carries its own identityId, so an org-wide listing can be grouped per identity without a second call.
Passing an identityId that isn’t your org’s returns 404 {"error": "identity not found"}. Omit it and there is no 404 to hit — the query is org-scoped, so another org’s mail is never included.
The org-wide listing is HTTP-only:
messages.list in both SDKs takes an identityId as its first argument, and sente inbox requires --identity. Use it for dashboards and audits; for “wait for the code that is about to arrive”, use wait above.Get a message
GET /v1/messages/:id
200: the full message object, including parsed and annotation. 404 {"error": "not found"} otherwise. This is the call to make after a message.received webhook, whose payload is only a summary.
Send an email
POST /v1/messages
Sends from the identity’s own address (DKIM-signed) and persists an outbound message.
201:
deliveryStatus: "sent" means the provider accepted it, not that it was delivered. Re-fetch the message later to see the delivery, bounce, or complaint outcome.
Both caps are checked before the mail provider is called, so a
402/429 never sent anything.
Archive and unarchive
POST /v1/messages/:id/archive · POST /v1/messages/:id/unarchive
Archiving is inbox hygiene: archived messages drop out of GET /v1/messages unless includeArchived=true, and are never matched by wait. Both are idempotent and return the updated message object. No body.
200: the message object with "archived": true. 404 {"error": "not found"} for an unknown id or another org’s message.
Related
Verification codes
The full OTP and magic-link flow.
Inbox
Send, reply, archive, and the org-wide feed.
Webhooks
Get pushed each inbound email instead of polling.
