Skip to content
MeridFlow AiFlow v8.x • self-hosted

API keys

Authentication covers the basics of how API keys work: what a scope is, what an agent scope does, and why the raw key is only shown once. This page is the full reference for managing keys: creating, listing, and revoking them.

These are admin actions

Every endpoint on this page requires an admin session token (see Authentication), not an API key. Creating or revoking a key is an admin operation. Using one day to day is what Sending events and the MCP server cover.

Create a key

Capped by your licence

This deployment's licence sets an api_keys limit. Creating one more past that cap returns 402 rather than succeeding; see Licence limits.

POST /api/v1/api-keys
Field Type Required Description
name string Yes A label to recognize this key by later, e.g. crm-integration.
agent_id integer or null No Scopes the key to one agent. Omit it (or send null) and the key works for every agent in the deployment.
scopes list of string No The permissions this key grants; defaults to ["events:write"]. See Scopes below.
expires_at datetime or null No An ISO 8601 timestamp after which the key stops working. Omit it for a key that never expires on its own.
curl -X POST https://api.your-domain.com/api/v1/api-keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{
        "name": "crm-integration",
        "agent_id": 1,
        "scopes": ["events:write"]
      }'
import httpx

response = httpx.post(
    "https://api.your-domain.com/api/v1/api-keys",
    headers={"Authorization": f"Bearer {admin_token}"},
    json={
        "name": "crm-integration",
        "agent_id": 1,
        "scopes": ["events:write"],
    },
)
response.raise_for_status()
key = response.json()["key"]
const response = await fetch("https://api.your-domain.com/api/v1/api-keys", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${adminToken}`,
  },
  body: JSON.stringify({
    name: "crm-integration",
    agent_id: 1,
    scopes: ["events:write"],
  }),
});
const { key } = await response.json();

The response includes the raw key exactly once. See the warning on Authentication if this is new to you: there's no way to retrieve it again afterward.

List keys

GET /api/v1/api-keys

Returns every key's metadata, never the raw key itself:

curl https://api.your-domain.com/api/v1/api-keys \
  -H "Authorization: Bearer $ADMIN_TOKEN"
import httpx

response = httpx.get(
    "https://api.your-domain.com/api/v1/api-keys",
    headers={"Authorization": f"Bearer {admin_token}"},
)
response.raise_for_status()
keys = response.json()
const response = await fetch("https://api.your-domain.com/api/v1/api-keys", {
  headers: { Authorization: `Bearer ${adminToken}` },
});
const keys = await response.json();
[
  {
    "id": 7,
    "name": "crm-integration",
    "agent_id": 1,
    "key_prefix": "af_live_a1b2c",
    "scopes": ["events:write"],
    "is_active": true,
    "last_used_at": "2026-01-15T10:30:00Z",
    "expires_at": null
  }
]

Use key_prefix (the full key's first 12 characters) to recognize a specific key later, in logs or in this list, without seeing the full value again after creation.

Revoke a key

DELETE /api/v1/api-keys/{id}
curl -X DELETE https://api.your-domain.com/api/v1/api-keys/7 \
  -H "Authorization: Bearer $ADMIN_TOKEN"
import httpx

response = httpx.delete(
    "https://api.your-domain.com/api/v1/api-keys/7",
    headers={"Authorization": f"Bearer {admin_token}"},
)
response.raise_for_status()
const response = await fetch("https://api.your-domain.com/api/v1/api-keys/7", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${adminToken}` },
});

Returns 204 No Content. Revocation is immediate: any request already using that key starts failing with 401 on its next call.

Scopes

Scope Grants
events:write Send events to an agent's events endpoint. This is the default scope for a new key. See Sending events.
mcp:calls Call place_outbound_call on the MCP server.
mcp:knowledge Call search_knowledge_base.
mcp:transcripts Call fetch_call_transcript.
mcp:agents Call list_agents and get_agent_status.
mcp:events Call record_event.
mcp:recall Call lookup_end_user.
mcp:custom_tools Call call_custom_tool.
mcp:orchestrate Call delegate_task_to_orchestrator.
mcp:tools Legacy alias, still accepted, for mcp:calls plus mcp:knowledge plus mcp:transcripts.

A key can hold more than one scope. There is no mcp:* wildcard: a key reaches exactly the tools its explicit scopes name. The mcp:* scopes tied to a licensed feature (mcp:events, mcp:recall, mcp:custom_tools, mcp:orchestrate) also need that feature enabled on the deployment.

No scope grants both key management (creating or revoking other keys) and key usage: managing keys is always an admin action, regardless of what scopes the key itself carries.