API key security
Choose the narrowest scope, keep test and live keys apart, store secrets outside your repository, and rotate on a schedule.
A Mailfully API key is a bearer credential: whoever holds the secret can do everything the key's scope allows.
Scope every key down
Seven scopes can be minted onto an API key; manage:keys is session-only and never reaches a key. Mint the narrowest one the calling code needs; Authentication says how scopes are checked and what a mismatch returns.
| Scope | Unlocks | On API keys |
|---|---|---|
send | POST /v1/emails and /v1/emails/batch, cancel and reschedule; template create, update, delete; domain create, verify, tracking, delete, turn receiving on or off; also satisfies email, template, and domain reads | Yes (the default) |
read:emails | GET /v1/emails, GET /v1/emails/{id}, GET /v1/emails/{id}/events; also template and domain reads | Yes |
read:inbound | GET /v1/emails/receiving and every route under it: received mail, its content, and attachments | Yes |
read:analytics | Analytics reads | Yes |
read:suppressions | Suppression list reads | Yes |
manage:webhooks | Webhook endpoint CRUD, deliveries, dead letters, replay | Yes, live keys only (opt-in) |
manage:suppressions | Add and remove suppressions | Yes, live keys only (opt-in) |
An analytics dashboard that only renders charts needs read:analytics and nothing else: mint that scope alone rather than reusing a send key that could also dispatch mail.
Keep test and live apart
A key's secret starts mf_live_ or mf_test_, and that prefix partitions your message data: messages, events, analytics rollups, and the keys themselves are scoped to both your org and the key's environment. A test key cannot read or send as live. Templates, domains, webhooks, and suppressions are shared by both environments, so a leaked test key carrying the default send scope can still change live templates and domains. For the same reason a test key cannot hold manage:webhooks or manage:suppressions: creating one returns 422 validation_error. Test and live environments says exactly where the boundary falls, and Test mode covers how test sends behave.
Where to keep the secret
Store a key's plaintext in an environment variable or a secret manager, and load it from there at runtime. Never commit it to source, never embed it in a client-side bundle, and never write it to a log line. A secret in a browser tab is visible to anyone who opens developer tools; see Calling the API from a browser.
Rotate on a schedule
Rotating mints a new secret and keeps the old one authenticating for a 24-hour grace window, so instances still running the old secret keep working while you deploy the new one. After the window closes, the old secret fails with 403 invalid_api_key ("This API key has been revoked.").
Rotate from the dashboard: open API keys, click Rotate on the key, then Rotate key in the dialog. Copy the new secret from the Your new API key dialog; it is shown once. See Rotate an API key for the endpoint contract.
Revoke when you must
Revoking is immediate: the key is rejected on its very next call with 403 invalid_api_key ("This API key has been revoked."). Revoking a key that is mid-rotation ends its grace window at once. Revoking a key that is already revoked is safe and keeps the original timestamp. In the dashboard, click Revoke on the key, then Revoke key.
If a key leaks
Whether to rotate or revoke first, and in which order, changes how long an exposed key stays live. See A leaked API key for the containment steps.
