Skip to content
Documentation menu
docs / api / post-v1-keys
self-serve

POST/v1/keys

Public. No key, and no quota deducted.

Call it

bash
curl -fsS -X POST "https://api.mapmap.ai/v1/keys" \
  -H "Content-Type: application/json" \
  -d @request.json

Request body

application/json · IssueKeyRequest

FieldTypeRequiredDescription
accept_tosnot statednoMust be literally true, anything else is a 400 echoing the terms-of-service URL.
allowed_originsstring[]noOrigins this key may be called from, e.g. ["https://app.example.com", "https://*.staging.example.com"]. At most 20; each is scheme://host[:port] with no path, and a wildcard may only stand for a single subdomain label. Omit for an unrestricted key, the default, and what a server-to-server integration wants.
device_idstringnoEmail-less issuance only: an opaque, stable id for the app install (the apps' install id). Never stored as sent; only its hash is used, as a per-install daily issuance budget beside the per-IP one. At most 128 characters. Optional, and ignored when an email is given.
emailstringnoEmail address; becomes the (lowercased) identity of the key. Optional ONLY for the MapMap apps' own labels ([identity::EMAIL_OPTIONAL_LABELS]), which then get an email-less anonymous key; every other caller must send one.
labelstringnoOptional human-readable label for this key (shown on the account page, e.g. "nightly-dispatch-agent"). Defaults to the email.
scopestringno"full" (the default) or "maps". A maps key may draw tiles, read styles/fonts/sprites, geocode and read its own status, and nothing else.
sourcestringnoOptional channel tag naming where this signup came from ("chatgpt", "agent-recipe", "cursor" …). Lowercased and restricted to [a-z0-9._-], at most 40 characters; anything else is dropped, never rejected, attribution must not break signups.

Responses

201Provisional key issued; the key field is shown once only
FieldTypeRequiredDescription
allowed_originsstring[]noThe canonical origin allow-list stored for this key, echoed back so the caller can see exactly what was accepted (ports and case are normalised, duplicates dropped). Absent on unrestricted keys.
callsintegeryesCall allowance: in total until verified for a provisional key, per calendar month for anonymous and verified keys.
claim_urlstringnoZero-authority claim pointer for the HUMAN behind this agent: the page shows a masked email and offers to send a sign-in link. Safe to print in chat or logs; it grants nothing by itself. Present only when the deployment has a console (SN_CONSOLE_URL).
display_to_userstringnoSentence for the agent to show its human verbatim (contains the claim URL, never the key). Present only alongside claim_url.
expires_in_hintegeryesHours until the provisional key expires unverified; 0 for keys that do not expire.
keystringyesThe full API key (snk_…). Shown once, never again.
key_idstringyesKey id (UUID), for /v1/keys/self correlation and admin ops.
scopestringno"maps" when the key was minted map-scoped; absent for the full surface.
statestringyesprovisional at an ordinary issuance; anonymous for an email-less app key; verified for the store-review identity.
tosstringyesTerms-of-service URL that was accepted.
verifystringyesWhat happens next.
400ToS not accepted (body echoes the tos URL), invalid/disposable email, or rejected allowed_origins/scope (body carries problems[])
429Issuance velocity exceeded: per IP or per install (limit_per_day), per address per hour for a key without an email (limit_per_hour), or the global hourly ceiling

Error bodies follow the shared problem model documented on API conventions.

Also under self-serve

Generated from https://api.mapmap.ai/openapi.json on 2026-11-01 · operationId issue_key