Authentication
Authenticate every request with a workspace API key in the Authorization header, and check it works in one call.
Every request to the public API carries a workspace API key in the Authorization header, with the Api-Key scheme:
Authorization: Api-Key mc_...There are no sessions, cookies or OAuth flows to set up for server-to-server work. A key belongs to exactly one workspace, so it can only ever read and write that workspace's data, and its scopes decide which parts of it.
Get a key and test it
Create a key
In the app, open Settings → API Keys and create a key. Give it only the scopes your integration needs; for this test, workspace:read is enough. Creating keys needs the Owner or Admin role.
The full key is shown once. Copy it into your secret store or an environment variable straight away:
export MAILCRATE_API_KEY="mc_..."Make a request
GET /public/workspace returns the workspace the key belongs to. It is the quickest way to prove a key works:
curl https://api.mailcrate.io/public/workspace \
-H "Authorization: Api-Key $MAILCRATE_API_KEY"Read the answer
A 200 with your workspace's id and name means the key is good. Anything else is one of the failures below.
When a key is rejected
Each request is checked in this order: the key, then its rate limit, then its scopes. The first check that fails answers, and nothing in your request runs.
| Status | Body message | What to do |
|---|---|---|
401 | "Unauthorized" | The Authorization header is missing, or does not start with Api-Key (note the space). |
401 | "Invalid API Key" | The key is unknown, revoked or expired. An expired key answers exactly like an unknown one. Create or rotate a key. |
403 | API key is missing required scope "sending:write" | The key is valid but lacks the scope this endpoint needs. The message names it. Add the scope, or use a key that has it. |
429 | API key rate limit exceeded (...) | The key spent its budget. Wait for Retry-After. See Rate Limits. |
429 | Varies | Too many invalid keys came from your IP address, so it is in a short cooldown. Fix the key, then wait for Retry-After. |
{
"message": "Invalid API Key",
"error": "Unauthorized",
"statusCode": 401
}The required scope for every endpoint is listed on its page in the API Reference.
Keep keys secret
- Server side only. A key in a browser bundle or mobile app is a key anyone can read. Call Mailcrate from your backend.
- One key per integration. Each key has its own rate-limit budget and its own audit trail, and you can revoke one without breaking the others.
- Rotate when in doubt. A key that may have leaked into a log, screenshot or commit should be rotated. The old key stops working the moment you rotate it.
Other credentials
Most integrations only ever need a workspace key. Three other kinds of credential reach the public API:
- Organization keys (
mco_...) authenticate the organization management plane under/public/organization/*: provisioning tenant workspaces and minting keys for them. They use the sameAuthorization: Api-Keyheader, and are refused everywhere else. See the Organization section of the API Reference. - OAuth access tokens (
mca_...) are what an AI client gets when it connects to the remote MCP server. You do not create these yourself. - Single-purpose tokens in a URL need no key at all. Journey webhook trigger URLs (
/hooks/journeys/<token>), unsubscribe and preference links, and campaign approval links each carry a token that unlocks exactly one action and nothing else.