Skip to main content
A team API key is a long-lived secret that lets a server, script, CI job or the mio CLI call the API for one team without a user signing in. Keys start with mio_sk_live_ and are sent as a bearer token. Each key is bound to the team that created it and cannot reach any other team. See Authentication for when to use a key instead of a signed-in user’s token.
Prefer the UI? The API keys page in the admin does everything on this page. See Manage API keys in the admin.

Rules to know before you start

  • Only the team owner can manage keys, and only while signed in. Creating, listing, reading, changing and revoking keys all need the team owner’s platform access token (a JWT). Other team members get 403. An API key cannot manage keys at all, not even its own, so a leaked key can never create a fresh key or revoke the others.
  • The secret is shown once. The create response is the only response that contains the full key, in data.attributes.secret. Store it straight away. If you lose it, revoke the key and create a new one.
  • Only the permission flags can change. A key’s name, scopes and expiry are fixed when you create it. To change them, create a new key and revoke the old one.
  • Revoking is permanent, and the key stays listed. A revoked key keeps its row, with revoked_at set, and every request made with it fails from then on.

Before you begin

Sign in as the team owner to get an access token, as shown in Sign in as a creator, and find your team id with GET /api/v1/teams. Then set:

Key format

A key looks like mio_sk_live_ followed by 43 random characters, 55 characters in all. The API stores only a hash of the full key. It keeps the first 24 characters in key_prefix (for example mio_sk_live_Zx9QmT4vLp2W) so you can tell keys apart in a list.

Attributes

A key is active until it expires or is revoked. There is no status attribute: work it out from revoked_at first, then expires_at.

Create a key

Send a name. Every other field is optional: The endpoint accepts a flat body or a JSON:API envelope. Both do the same thing. Flat body:
JSON:API envelope:
In the envelope, type must be api_keys and attributes may hold only the fields in the table above. Anything else returns 422. Success is 201 Created. This is the only response that includes secret:
Store secret as soon as you receive it, in a secret manager or your CI’s secret store. No later response returns it, and there is no way to recover it. If it is lost, revoke the key and create a new one.
To create a key and keep its secret in your shell in one step:
Reference: Mint Api Key

Scopes

scopes defaults to ["*"], which means full access to the team. "*" is the only scope today, so leave scopes out or send ["*"]. Any other value, or an empty list, is rejected with 422 when you create the key. Keys created before scopes were enforced could hold any list, such as [] or ["contacts:read"], and still had full access, because nothing read scopes. When enforcement shipped, every key that wasn’t revoked was set to ["*"], so those keys kept the access they had and keep working. A key whose scopes are any list other than exactly ["*"] works nowhere: every request made with it returns 403 with the code api_key_scope_denied. Create a replacement key with the default scopes and revoke the old one.

Permission flags

Two opt-in flags let a key do things that no key can do by default. Both default to false. A signed-in team owner does not need them. Grant a flag when you create the key, or change it later with PATCH. For moderation from the mio CLI, see Moderation with an API key. Reference: List Moderation Queue · Ban Member · Admin Create Event · Admin Patch Event · Admin Cancel Event

List keys

The list includes both active and revoked keys, newest first. It never includes secret. There is no status filter, so select what you need yourself. For example, to show only keys that are not revoked:
The list uses cursor pagination:
  • page[size] sets the page size, from 1 to 100. The default is 20. A value outside that range returns 422.
  • While more keys remain, the response has meta.has_more: true and a links.next URL. Request that URL, or send page[after] with the id of the last key on the page, to get the next page.
See Pagination and filtering for how cursors work across the API. Reference: List Api Keys

Get one key

The response has the same attributes as a list item, without secret. A key id that is not in this team returns 404 with code api_key_not_found. Reference: Retrieve Api Key

Change permissions

PATCH changes the permission flags and nothing else. Send only the flags you want to change. A flag you leave out keeps its value.
The envelope form works too:
Success is 200 with the updated key. Things to know:
  • The body must contain can_moderate, can_author_events or both. A body with neither returns 422.
  • name, scopes and expires_at cannot be changed. Sending any of them, or any other field the endpoint doesn’t know, returns 422 in both a flat body and an envelope, with source.pointer naming the field, and nothing changes. To change them, create a new key, move your integration to it, and revoke the old one.
  • The change applies to the key’s next request. You do not need a new secret.
Reference: Update Api Key

Revoke a key

Success is 204 No Content. Revoking sets revoked_at and does not delete the key: it stays in the list so you can see when it was used last and when it was revoked. From that moment every request made with it returns 401 with code api_key_revoked. There is no undo. Revoking the same key again returns 409 with code api_key_already_revoked, and an unknown key id returns 404 with code api_key_not_found. Reference: Revoke Api Key

Use a key

Send the key as a bearer token, exactly as you would a platform access token:
The hubs list path ends with a slash. Without it the API answers with a 307 redirect and an empty body, which curl does not follow unless you add -L. A key works on its own team’s routes. What it cannot do:
  • Reach another team. Using it on another team’s routes returns 403. See Tenancy.
  • Do things that need a signed-in user. Managing API keys, creating or switching teams, and other account-level operations return 403 with “This operation requires user (JWT) authentication, not an API key.”
  • Use the moderation tools or author hub events unless the matching permission flag is on.
When a key is rejected, the error code tells you why: Every request that authenticates with a key updates its last_used_at. See Error handling for the error envelope.

Keep a way back in

Because a key cannot manage keys, you always need to sign in as the team owner to create a replacement key. Treat the owner’s password as the recovery path for every key the team has, even if your integration only ever uses keys.
Alpha: use Forgot your password from the admin sign-in page to request a reset. An API key cannot change an account password. Until MIO-4236 lands, a reset email is sent only when the account’s team has at least one hub. If you have no hubs and are locked out, contact support. If your team works only through the API, keep the owner password safe so you can create replacement keys.