Authentication
How requests are identified, and how to keep your credential safe.
Every request to the Mapier API carries an API key in the Authorization
header.
curl https://api.mapier.ai/v1/handle-check \
-H "Authorization: Bearer $MAPIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "address": "+14155550100" }'A request without one — or with a key that has been revoked or has expired — is rejected before anything else happens:
{ "error": { "code": "invalid_credentials", "message": "That API key is not valid." } }What a key looks like
A key is a prefix and 43 characters of base62:
mp_live_9Kq2… a live key — reaches a real line and real handsets
mp_test_Xa7v… a test key — reaches your project's sandbox and nothing elseThe prefix is the only readable part, and it is deliberate: a key's environment is in its name, so a test key pasted into a production deploy fails loudly rather than texting a customer, and a live key in a test harness is visible in the first log line. The two environments share no data — test mode says what a test key can and cannot reach.
Where keys come from
Keys are issued in the console, per project and per environment: Keys → Create key. The plaintext is shown exactly once, in the dialog that creates it, and never again — only a SHA-256 hash is stored, so there is nothing to look up later. Copy it into your secret manager before you close the dialog.
Each key carries a name, an optional expiry, and a last-used stamp the console
shows beside it, so an unfamiliar key that is still being used is one you can
see. A key is revoked from the same screen; a revoked key answers 401 on its
next request, whatever it was doing.
What a key identifies
A key maps to one project in one environment, and a live project maps
to the lines it holds — the real Apple accounts on real Macs that actually talk
to iMessage. One key sends from every line its project holds. You do not have
to choose: a person is answered on the number they last wrote to, and somebody
new gets the line the platform picks. When you do want to choose, name the line
at target.lineId — see Choosing the line.
Three consequences worth designing around:
- Every resource is project-scoped. A conversation id or attachment id from
another project returns
404, indistinguishable from one that does not exist. Existence is never revealed across projects. - A key is fully privileged within its project and environment. A key that can read the stream can also send messages. There is no per-key scoping.
- Keys share the project's command budget. Every key of a project spends one command ceiling per environment, so a second key is not more headroom. See Rate limits.
Handling the key
Store it outside your code
Put it in an environment variable or a secret manager. Never commit it, and
never ship it to a browser — the API is server-to-server, and there is no
public or publishable key. The console's own quickstart prints
MAPIER_API_KEY=<paste-your-key-here> rather than a value for the same reason.
export MAPIER_API_KEY="mp_test_…"Read it once at startup
const MAPIER_API_KEY = process.env.MAPIER_API_KEY;
if (!MAPIER_API_KEY) throw new Error("MAPIER_API_KEY is not set");Failing loudly at boot beats discovering it in a 401 under load.
Keep it out of logs
The key travels in a header, so anything that dumps request headers leaks it.
Redact Authorization in your logging middleware, and be careful with verbose
HTTP clients — curl -v prints the header in full.
A small client
Everything in these docs is plain HTTP, so a wrapper is a few lines:
const BASE = "https://api.mapier.ai";
export async function mapier(path: string, init: RequestInit = {}) {
const res = await fetch(`${BASE}${path}`, {
...init,
headers: {
Authorization: `Bearer ${process.env.MAPIER_API_KEY}`,
"Content-Type": "application/json",
...init.headers,
},
});
if (!res.ok) {
const body = await res.json().catch(() => ({}));
throw new Error(`${res.status} ${body.error?.code ?? "request failed"}`);
}
return res;
}The full surface, with every request and response shape, is the OpenAPI
document at https://api.mapier.ai/openapi.json — /v1 only, which is the
whole of what a key can reach.