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 a key
Section titled “Create a key”Create keys in the dashboard under Developer → API keys, or programmatically:
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.
Scopes
Section titled “Scopes”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.
Expiry and revocation
Section titled “Expiry and revocation”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.
Ownership, not just authentication
Section titled “Ownership, not just authentication”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.
Keep keys out of harm’s way
Section titled “Keep keys out of harm’s way”- 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 forbiddeneven with a valid key.