API Keys
Your backend needs to talk to Perfox — create an agent, upload a document to the Knowledge Base, read a transcript, send a WhatsApp message. API keys authenticate those server-to-server calls, and each key's scopes decide exactly what it is allowed to do.
Try the Platform API live
Browse and call every endpoint on this page — authenticated with your own key — in the API Explorer. The same operations are available to any MCP-capable agent in the MCP Explorer.
Creating a key
Open Developer in the Studio sidebar (under Admin) and stay on the API keys tab. Click + New key, give it a name, and tick the scopes it needs. (See the Developer Hub Guide for the rest of that page.)
A key looks like this:
sk_<64 hexadecimal characters>The full key is shown in a dialog once, right after you create it. Copy it into your secret manager then. In the key list you only ever see the sk_ prefix and the first eight characters, which is enough to tell keys apart.
From the key list's ⋯ menu you can:
| Action | What it does |
|---|---|
| Copy key | Copies the full key to your clipboard without showing it on screen. Keys created before secure copy existed have no copy option — rotate them once to enable it. |
| Rotate | Issues a new secret for the same key (same name, same scopes). The old secret stops working immediately, and the new one is shown once. |
| Delete | Revokes the key permanently. Requests using it fail from that moment. |
Authenticating a request
Send the key as a bearer token on every request to https://<your-workspace>-api.perfox.ai/api/v1/…:
Authorization: Bearer sk_<key>Each request is checked in this order:
- The header must be present and well-formed, and the key must exist — otherwise
401 invalid_api_key. - A key that is no longer active returns
401 revoked_api_key. - The key must carry the scope the endpoint requires — otherwise
403 insufficient_scope, with a message naming the missing scope. - The request must be within the rate limit — otherwise
429 rate_limited, with aRetry-Afterheader. The limit applies per key and across your whole workspace, over a one-minute window.
Routes are deny-by-default: a key can only call endpoints whose scope it was given.
Scopes
These are the scopes you can tick when creating a key. A new key starts with Structured document extraction, Read Knowledge Base and Upload & manage Knowledge Base pre-selected (plus Ingest customer memory, which no endpoint uses any more — untick it).
| Group | Scope | Label in the Studio |
|---|---|---|
| Agents | workflows:read | Read agents |
| Agents | workflows:write | Create & edit agents |
| Agents | workflows:publish | Publish agents |
| Knowledge Base | kb:read | Read Knowledge Base |
| Knowledge Base | kb:write | Upload & manage Knowledge Base |
| Customers | customers:read | Read customers |
| Customers | customers:write | Create & update customers |
| Conversations | conversations:read | Read conversations & transcripts |
| Conversations | conversations:write | Write conversations |
| Credentials | credentials:read | Read provider credentials |
| Credentials | credentials:write | Register provider credentials |
| MCP Servers | mcp_servers:read | Read MCP tool servers |
| MCP Servers | mcp_servers:write | Register MCP tool servers |
| Documents | documents:extract | Structured document extraction |
| Analytics | analytics:read | Read analytics |
| Support | support:read | Read support tickets |
| Support | support:write | Raise & reply to support tickets |
| Webhooks | webhooks:read | Read webhook subscriptions |
| Webhooks | webhooks:write | Manage webhook subscriptions |
Endpoints by scope
Every path below is under https://<your-workspace>-api.perfox.ai.
| Scope | Endpoints | Guide |
|---|---|---|
workflows:read | GET /api/v1/agents, GET /api/v1/agents/{id} | API Explorer |
workflows:write | POST /api/v1/agents, PATCH /api/v1/agents/{id}, POST /api/v1/agents/from-spec, POST /api/v1/agents/generate | API Explorer |
workflows:publish | POST /api/v1/agents/{id}/publish | API Explorer |
customers:read | GET /api/v1/customers, GET /api/v1/customers/{id} | API Explorer |
customers:write | POST /api/v1/customers, PATCH /api/v1/customers/{id}, POST /api/v1/customer/link | API Explorer |
conversations:read | GET /api/v1/conversations, GET /api/v1/conversations/{id}, GET /api/v1/conversations/{id}/events, GET /api/v1/cases, GET /api/v1/calls, GET /api/v1/calls/{id}, GET /api/v1/conversations/{id}/recordings, GET /api/v1/messages, GET /api/v1/messages/{id} | Conversations, Cases, Calls, Messages |
conversations:write | POST /api/v1/outbound, POST /api/v1/messages | Outbound, Messages |
kb:read | GET /api/v1/kb/files, GET /api/v1/kb/files/{id}, GET /api/v1/kb/files/{id}/download, GET /api/v1/kb/folders, POST /api/v1/kb/search | Knowledge Base |
kb:write | POST /api/v1/kb/files, DELETE /api/v1/kb/files/{id}, POST /api/v1/kb/files/{id}/move, POST /api/v1/kb/folders, PATCH /api/v1/kb/folders/{id}, DELETE /api/v1/kb/folders/{id} | Knowledge Base |
credentials:read | GET /api/v1/credentials, GET /api/v1/credentials/{id}, GET /api/v1/credentials/{id}/resources | Credentials |
credentials:write | POST /api/v1/credentials | Credentials |
mcp_servers:read | GET /api/v1/mcp-servers, GET /api/v1/mcp-servers/{id} | API Explorer |
mcp_servers:write | POST /api/v1/mcp-servers, PATCH /api/v1/mcp-servers/{id} | API Explorer |
documents:extract | POST /api/v1/documents/extract_structured | below |
analytics:read | GET /api/v1/analytics/summary, GET /api/v1/analytics/conversations-over-time, GET /api/v1/analytics/channel-breakdown, GET /api/v1/billing/credits, GET /api/v1/billing/usage | Analytics & Usage |
support:read | GET /api/v1/support/tickets, GET /api/v1/support/tickets/{id} | Support Tickets |
support:write | POST /api/v1/support/tickets, POST /api/v1/support/tickets/{id}/reply | Support Tickets |
webhooks:read | GET /api/v1/webhook-subscriptions | Messages & Webhooks |
webhooks:write | POST /api/v1/webhook-subscriptions, PATCH /api/v1/webhook-subscriptions/{id}, DELETE /api/v1/webhook-subscriptions/{id}, POST /api/v1/webhook-subscriptions/{id}/test | Messages & Webhooks |
The machine-readable description of all of these is served, without authentication, at GET /api/v1/openapi.json on your API host.
Structured document extraction
POST /api/v1/documents/extract_structured takes a document and a JSON Schema and returns the document's contents shaped to that schema. Send it as multipart/form-data:
| Field | Required | What |
|---|---|---|
file | yes | PDF, DOCX, TXT, PNG, JPEG or WEBP. Anything else returns 415 unsupported_mime. |
schema | yes | A JSON Schema, as a JSON string. Missing → 400 missing_schema; not a JSON object → 400 bad_schema. |
prompt | no | Extra instructions for the extraction. |
Worked example — uploading a file to the Knowledge Base
Setup: Asha, an admin at Acme Support, wants her deployment pipeline to push the latest product manual into Perfox automatically. She creates a key with only the Upload & manage Knowledge Base scope and stores it as PERFOX_API_KEY.
Action: Her pipeline runs:
bash
curl -X POST https://acme-support-api.perfox.ai/api/v1/kb/files \
-H "Authorization: Bearer $PERFOX_API_KEY" \
-F "file=@product-manual-v3.pdf" \
-F "folder_id=fld_abc123"Result: Perfox returns 201 with the new file's id and status: "pending". Indexing runs in the background; the pipeline polls GET /api/v1/kb/files/{id} until the status is active.
What just happened: The key carried kb:write, so it passed the scope check. Had the pipeline called POST /api/v1/outbound, it would have received 403 insufficient_scope — the key simply cannot do that, whoever holds it.
Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The body or query parameters failed validation; message names the field. |
| 401 | invalid_api_key | Key missing, malformed, or does not match. |
| 401 | revoked_api_key | Key exists but is no longer active. |
| 403 | insufficient_scope | Key is valid but lacks the scope this endpoint requires. |
| 404 | not_found | The id in the path does not exist in your workspace. |
| 429 | rate_limited | Too many requests; wait for the number of seconds in Retry-After. |
Every error body has the same shape: { "error": "<code>", "message": "<detail>" }, sometimes with extra fields that are documented on the endpoint.
Next steps
- Knowledge Base — upload, search and organise documents from your own systems.
- Messages & Webhooks — send WhatsApp messages and receive inbound messages on your endpoint.
- Site Management — the separate keying for the embeddable chat widget.