Authentication
How requests are identified, and how to keep your credential safe.
Every request to the Mapier API carries a credential in the Authorization
header.
curl $MAPIER_BASE_URL/v1/handle-check \
-H "Authorization: Bearer $MAPIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "address": "+14155550100" }'A request without one is rejected before anything else happens:
{ "error": "unauthenticated" }Unconfirmed
The credential scheme is not final. Key issuance, rotation and per-key scoping are still being designed, and the exact header may change before general availability.
During preview, your credential and the header to send it in are issued to you
together — contact Mapier for access. If what you were given does not match
the Authorization: Bearer form shown here, follow what you were given; these
examples show the intended shape.
Write your client so the credential and the header name are read from configuration. When the scheme settles, nothing but that configuration changes.
What a credential identifies
One credential maps to one account, and an account maps to one Mac connector — the machine that actually talks to iMessage. This is why the API has no "which number am I sending from" parameter: your account already determines it.
Two consequences worth designing around:
- Every resource is account-scoped. A conversation id or attachment id from
another account returns
404, indistinguishable from one that does not exist. Existence is never revealed across accounts. - There is no per-key scoping yet. A credential that can read the stream can also send messages. Treat it as fully privileged.
Handling the credential
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.
export MAPIER_API_KEY="..."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 credential 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 = process.env.MAPIER_BASE_URL!;
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 ?? "request failed"}`);
}
return res;
}Keeping the base URL in configuration matters more than usual here, because the production hostname has not been assigned yet.