MailcrateDocs

API Keys & Scopes

How scopes restrict what a workspace API key can read and write on the public API, and how keys expire and rotate.

Every workspace API key carries a set of scopes that determine which resources it can read and write on the public API. Scopes keep a key limited to what your integration actually needs — a key used only to send transactional mail, for example, doesn't need to be able to read your contact list or rewrite your sending domains.

Who can manage keys

Anyone in the workspace can see the key list under Settings → API Keys. That list shows each key's prefix, scopes, expiry and creation date — never the key itself — so a developer debugging a failing integration can check which key it is authenticating as without needing elevated access.

Creating, rotating and revoking a key requires the Owner or Admin role. Each of those actions hands out or destroys a credential that can act on the whole workspace, so they sit at the same level as inviting a member. A member who attempts one gets 403 Forbidden; in the dashboard the actions are visible but disabled.

Scope format

A required scope has the form:

resource:action

action is derived from the HTTP method of the request:

  • read — required for GET and HEAD requests.
  • write — required for POST, PUT, and DELETE requests.

So, for example, listing campaigns requires campaign:read, while sending one requires campaign:write.

A key can also carry the special full_access scope. A key with full_access bypasses per-resource scope checks entirely and can read and write every resource below — use it sparingly, and prefer narrowly scoped keys for anything that isn't a first-party integration you fully trust.

Available scope resources

ResourceReadWriteCovers
contact✓✓Contact records, their properties, and activity timelines.
segment✓✓Segments and their computed membership.
subscription-group✓✓Subscription groups and a contact's opt-in/opt-out state in each.
campaign✓✓Creating, scheduling, and sending broadcast campaigns.
journey✓✓Journeys, and enrolling or exiting contacts.
sending✓✓Sending transactional and batch mail through the API.
delivery✓✓Per-recipient delivery status — opens, bounces, and complaints.
event✓✓Recording and reading custom contact events.
webhook✓✓Configuring event webhook subscriptions.
email-template✓✓Email templates, including pushing new versions via the CLI.
sender-identity✓✓Verified sender identities used as the "from" address on sends.
sending-domain✓✓Verified sending domains and their DNS/authentication status.
suppression✓✓The workspace's global suppression list.
external-audience✓✓Externally-hosted audiences used as a recipient source.
inbound✓✓Inbound addresses and mail routed into the workspace.
rendering✓✓Rendering template previews without sending mail.
workspace-branding✓✓Logo, colours, and the branding applied to hosted pages and emails.
hosted-page-domain✓✓Custom domains serving hosted pages such as the subscription centre.
workspace✓✓Workspace identity, compliance postal address, quota usage, sending status, and review state. Write access changes only the postal address.
full_access——Grants read and write on every resource above; bypasses per-resource checks.

Example

A request to list deliveries, authenticated with a key that carries delivery:read:

curl https://api.mailcrate.io/public/delivery \
  -H "Authorization: Api-Key <api_key>"

If the key is missing the required scope, the request is rejected by the scope guard before it reaches the delivery endpoint — see Authentication for how the API-key and scope guards fit together.

Expiry

A key can be given an expiry date when it is created. Keys created without one never expire, which is the default and the behaviour every key created before expiry existed still has.

Expiry is enforced at authentication time. Once a key is past its expiry date, every request it makes is rejected with 401 Unauthorized — the same response, with the same body, that an unknown key gets. That is deliberate: an expired key must not identify itself as a key that once existed.

An expired key is not deleted. It stays in the list, flagged as expired, so the reason an integration stopped working is visible rather than looking like a key that vanished. Rotating it issues a working replacement; revoking it removes it for good.

Pick an expiry that matches how the key is used. A key handed to a third party, a contractor, or an AI agent is a good candidate for a short life; a key embedded in a long-running production service is usually better served by a deliberate rotation schedule than by an expiry that will page someone at an inconvenient hour.

Rotation

Rotating a key issues a replacement carrying the same name and scopes and retires the original in the same operation. The new key's full value is returned exactly once, in the rotation response, exactly like creation:

curl -X POST https://api.mailcrate.io/workspace/api-keys/<key_id>/rotate \
  -H "Authorization: Bearer <dashboard_session>"

Three things are worth knowing before you rotate:

  • The old key stops working immediately. There is no grace period and no overlap window. Anything still presenting the old key starts getting 401 from the moment the rotation returns, so have the new value ready to deploy before you rotate a key that is in active use.
  • The replacement is a new key, with its own id and its own prefix. Its usage history and rate-limit budget start fresh; the retired key's audit trail stays intact under its own id.
  • Expiry carries forward as a duration, not a date. A key created with a 90-day life rotates into another 90 days starting now — not into a key that expires when the original would have, which would often be within hours of the rotation. A key that never expires rotates into another key that never expires.

The rotation body controls the replacement's expiry, and it distinguishes three cases:

BodyReplacement expires
{} — field absentInherits the original's lifetime, measured from now
{"expiresAt": "2027-01-01T00:00:00Z"}On that date. Must be in the future
{"expiresAt": null}Never — this is how an expiring key is promoted to a permanent one

Note that omitting the field and sending null are not the same instruction.

Rotation is the right response to a key that may have been exposed — in a log, a screenshot, a commit, or a departing contractor's terminal history — and to a key nearing its expiry date. Revocation, which issues no replacement, is for a key you no longer need at all.

Keys for AI agents

Scopes are how you bound what an agent can do with your workspace. A key given to an MCP client is the only thing standing between "summarise my campaign stats" and "send this campaign" — see CLI & MCP for the recommended split.

On this page