Authentication
Every request to the Mailgrid API is authenticated with a Bearer token tied to exactly one tenant.
API keys
Keys look like:
mb_live_V8PKa7eVodFXiRohbWio_kxDsW2JpVZRqddIhwism1F3 └┬┘ └┬─┘ └────────────────┬────────────────────────┘ │ │ └ secret (24 bytes base64url) │ └ env: live or test └ Mailgrid prefix
The first 12 base64url characters of the secret form an indexed prefix we cache in KV for sub-millisecond lookup. The full token is HMAC-SHA256 hashed against your API_KEY_HMAC_SECRET and compared in constant time.
Presenting the key
Pass the token as a Bearer header on every request:
curl https://api.mailgrid.space/api/streams \ -H "Authorization: Bearer mb_live_..."
Scopes
Each key carries a list of scopes. The bootstrap key has admin (all scopes). Issue narrower keys for specific use cases:
| Scope | Grants |
|---|---|
emails:send | POST /api/emails, /batch, /schedule, /smtp/send |
templates:read / templates:write | Template CRUD |
streams:read / streams:write | Email streams |
files:read / files:write | File Cache |
users:read / users:write | Team management |
ips:read / ips:write | Dedicated IP mapping |
domains:read / domains:write | Domain identities |
events:read | Event log + analytics |
ai:use | AI endpoints (summarize, ask, personalize) |
knowledge:read / knowledge:write | Knowledge base |
labels:read / labels:write | Label rules |
audit:read | Audit logs |
agents:dispatch | POST /api/agents/dispatch, /api/mcp |
admin | Implicit grant for everything |
Rotating keys
To rotate, create a new key while the old one is still active, deploy the new key to your systems, then revoke the old one. There's no downtime in this flow because both keys remain valid until you explicitly revoke.
Never commit API keys to source control. Use Cloudflare Workers secrets, AWS Secrets Manager, GCP Secret Manager, or your platform's equivalent.
Public endpoints
These don't require auth:
GET /healthGET /readyGET /openapi.jsonPOST /api/webhooks/ses(SNS signature-verified instead)GET /t/o/:token,GET /t/c/:token(tracking)GET|POST /unsubscribePOST /api/users/accept-invite(token-gated)