Skip to content

Authentication

Every request to https://app.maukirim.com/api/v1 authenticates with an API key sent as a bearer token:

Authorization: Bearer mk_live_…

The scheme name is case-insensitive. Exactly one token may follow the space. A request with no header, a malformed header, or a key that does not exist is refused with 401 api_key_invalid.

Create keys in the dashboard under Developer → API keys, or programmatically:

Terminal window
curl -X POST https://app.maukirim.com/api/developer/api-keys \
-H "Content-Type: application/json" \
-H "Cookie: maukirim-session=…" \
-d '{ "name": "Production backend", "scopes": ["otp", "notification"], "expiresInDays": 365 }'

That endpoint requires a signed-in session, not an API key — a key cannot mint another key. If you would rather do this from an AI assistant, the MCP server can create keys for you under a stricter rule (see below).

The response contains the key value exactly once:

{ "ok": true, "key": { "id": "key_…", "name": "Production backend", "prefix": "mk_live_AbCd" }, "secret": "mk_live_…" }

Store it in your secret manager immediately. MauKirim keeps only a SHA-256 hash, so there is no way to read a key back — if you lose it, revoke it and create another. The dashboard shows mk_live_ plus the first and last four characters so you can tell keys apart.

A key carries a set of scopes. A route fails closed unless the key holds the scope that route requires.

Scope Grants
otp POST /otp/send, POST /otp/verify
notification POST /messages/send
read GET /devices, GET /devices/{id}
send POST /devices/{id}/messages
device PATCH /devices/{id}/profile, POST /devices/{id}/presence, POST /devices/{id}/chat-presence
webhook GET/POST/PUT/DELETE /devices/{id}/webhook, GET /webhook-deliveries
gmb Google Business: every change — PATCH /gmb/locations/{id}, review replies, POST /gmb/locations/{id}/refresh, posts, photos, attributes, verification, the POST /gmb/locations/{id}/google door, creating connect sessions and registering return addresses, POST /gmb/locations/activation (turning businesses on or off), and DELETE /gmb/connections/{id}. It also covers every Google Business read, which read covers too

The gmb scope is the Google Business connector’s write scope. Reading businesses, connections, reviews, posts, photos, insights, attributes, categories, verification history, managers, connect sessions, return addresses, jobs, usage and quota needs read or gmb. Everything that changes what the public sees on Google (editing a listing, replying, posting, adding or deleting photos, changing attributes, starting or completing a verification), spends the shared Google budget on a refresh, or changes who may connect (creating a connect session, registering or removing a return address, disconnecting a connection) needs gmb. So does the Google door for every method, even GET, and POST …/verifications/options, which is a POST at Google even though it changes nothing. The account’s package must also include the connector (Growth and above), or the answer is 402 gmb_plan_required whatever the scope. See Google Business Profile.

Requesting a scope the route needs but the key lacks answers 403 api_key_scope_denied. Create one key per service or per environment and grant only what it needs: a key that can only otp cannot send notifications or rent anything, so a leak in your OTP service does not expose the rest.

expiresInDays Meaning
0 never expires
30, 90, 365 expires that many days after creation

An expired key answers 401 api_key_expired; a revoked key answers 401 api_key_revoked. Revoke from the dashboard the moment a key is no longer needed. Rotation is: create the new key, deploy it, then revoke the old one — there is no overlap period built in, so both are valid until you revoke.

MauKirim records a last used at timestamp per key (updated at most about once a minute), so you can see which keys are still in use before revoking.

An authenticated key still only reaches its own account’s resources. For the rented-number routes, a device that belongs to another account answers 404 rental_not_found — deliberately identical to a device that does not exist, so the API never reveals which device ids are real.

  • Send keys only from a backend. Never ship one to a browser or a mobile app: a bearer token in a client is a bearer token in everyone’s hands.
  • Every key is scoped, so the blast radius of a leak is the scopes it holds.
  • The caller’s account status also matters: if the account is suspended, every request answers 403 forbidden even with a valid key.