Reference
Tags and metadata
Support questions arrive in your vocabulary — a plan, a tenant, a job — and a delivery log you can only search in ours is a log somebody has to translate. Label a message on the way out and it comes back the same way.
Two fields, different jobs
| Field | Shape | For |
|---|---|---|
tags | Up to 10 labels, 64 characters each | A small, low-cardinality label set you filter on directly. |
metadata | Up to 20 string key/value pairs | Ids you round-trip through us and match exactly. |
Tags are normalised — trimmed, lowercased, deduplicated. A tag exists to be filtered on, and Password-Reset matching nothing while password-reset matches everything is the kind of surprise that stops people trusting a log.
Metadata values must be strings. JSON gives us no way to tell 42 from "42" on the way back out of a field we promised to hand back unchanged, so send "42" and parse it yourself.
Filtering
?tag= is repeatable, and repeating it means both — narrowing a search never widens the result. ?metadata=key:value matches exactly; there is no prefix or substring form, because the index answers containment and a LIKE here would be a full table scan offered politely through the public API.
A value may itself contain a colon — ?metadata=callback:https://x.test:8443/h splits on the first one only.
They come back on every webhook
Both are echoed on events about the message, so a receiver can route the event without looking the id up first. Empty rather than absent when the message carried none — you should not need one guard for the webhook and a different one for the message you fetch afterwards.
{
"id": "evt_AZLm…",
"type": "delivered",
"createdAt": "2026-08-25T12:00:00.000Z",
"data": {
"messageId": "msg_AZLm…",
"tags": ["password-reset"],
"metadata": { "userId": "u_1234", "tenant": "acme" },
"detail": { }
}
}Not the place for a secret
Neither field is encrypted at rest, unlike the message body. Both exist to be queried, and an encrypted column cannot be. Put an order id here, not a one-time passcode.
Both are deleted with the delivery record by the ordinary retention purge, so they last exactly as long as your plan’s retention period — unlike the body, which purges at 30 days regardless.
Examples
POST /v1/emails
{
"from": "[email protected]",
"to": "[email protected]",
"subject": "Reset your password",
"text": "…",
"tags": ["password-reset"],
"metadata": { "userId": "u_1234", "tenant": "acme" }
}NextMessages and the waybill →Read back a message, its status, its events and the SMTP conversation.