API Key Permissions
The four Koji API key permissions in depth, with least-privilege key recipes for client-side and server-side integrations.
API Key Permissions
Every Koji API key carries a permission set chosen when the key is created. The four permissions map one-to-one onto the four interview endpoints, which makes least-privilege keys easy to reason about: a key can do exactly what its scopes say and nothing else. This guide covers each permission, what a missing permission looks like on the wire, and the key setups we recommend.
The four permissions
| Permission | What it does | Grants |
|---|---|---|
interview:start | Start interviews | POST /interviews/start |
interview:chat | Send messages | POST /interviews/{id}/message |
interview:complete | Complete interviews | POST /interviews/{id}/complete |
interview:read | Read interview data | GET /interviews/{id} |
interview:start
Grants POST /interviews/start. This is the entry point of every integration: it creates the interview session and returns the session_token your client needs for the rest of the conversation. See Starting Interviews via API.
interview:chat
Grants POST /interviews/{id}/message. The message endpoint requires this scope on the API key, plus a valid X-Session-Token header proving the request belongs to the respondent's session. See Sending Messages via API.
interview:complete
Grants POST /interviews/{id}/complete. Marks the interview finished and triggers AI analysis in the background. Like the message endpoint, it needs both the key scope and the session token. See Completing Interviews via API.
interview:read
Grants GET /interviews/{id}. Returns the full transcript, respondent info, stats, and analysis. It authenticates with the API key alone: no session token required. That makes it server-to-server friendly, and also the scope you should guard most carefully.
The full credential matrix
Permissions are only half of each endpoint's auth story. This is the complete picture, including the embed bootstrap endpoint, which is the one /api/v1 endpoint with no permission scope (its optional API key only authenticates the prefill lookup):
| Endpoint | API key | Session token | Permission |
|---|---|---|---|
POST /interviews/start | Yes | No | interview:start |
POST /interviews/{interview_id}/message | Yes | Yes | interview:chat |
POST /interviews/{interview_id}/complete | Yes | Yes | interview:complete |
GET /interviews/{interview_id} | Yes | No | interview:read |
GET /embed/{project_id} | Optional | No | None |
What a missing permission looks like
Calling an endpoint with a key that lacks its scope returns HTTP 403 with this exact body:
{
"error": "API key does not have interview:read permission"
}
The error string names the missing scope, so it tells you precisely which permission to add. There is no code or details field anywhere in the API: match on the HTTP status and the error string. See Common Error Codes.
Least-privilege recipes
Client-side widget key
For a browser integration that drives the conversation itself, create a key with:
interview:startinterview:chatinterview:complete
Leave interview:read off. The browser needs to run the conversation, but it should never be able to read back transcripts or analysis. Pair this key with an origin allowlist so other sites cannot reuse it (see API Authentication).
Server analytics key
For a backend job that pulls results into your warehouse or dashboards, create a key with:
interview:read
If this key ever leaks, the holder can read interview data for one study but cannot create, drive, or complete interviews.
Full-lifecycle server key
A backend that both triggers interviews and collects results (see Research Automation) can hold all four permissions. Keep it strictly server-side.
Choosing permissions at creation
Open your study, click the three-dot menu → Integrate → Advanced tab → API Keys → Create API Key. Select the permissions the key needs at creation; new keys default to all four.
Narrow the set before you create the key. To change a key's scope later, create a new key with the set you need and revoke the old one.
Keys and session tokens work together
Permissions live on the API key, which is your developer credential: it says which study you are talking to and which operations the caller may perform. The session token is a separate respondent credential:
- Issued by the start endpoint as
session_token. A bare UUID (no prefix). - Scoped to a single interview session; required on the message and complete endpoints.
- Acts as the respondent-side credential: treat it as a secret for that interview.
- The read endpoint (GET /interviews/{id}) does not need it. It authenticates with the API key alone.
The message and complete endpoints check both. A key with the right scope but a wrong token fails with 401 Invalid session token; a valid token with a key missing the scope fails with the 403 shown above. The two checks are independent, which makes failures easy to attribute.
FAQ
Can I add a permission to an existing key?
Permissions are selected in the create dialog. To broaden or narrow a key's scope, create a new key with the right set and revoke the old one.
Why does interview:read not need a session token?
It is designed for server-to-server retrieval after the respondent's session is over. The API key alone authenticates it, which is exactly why read access belongs on server-side keys only.
My key has interview:chat but requests still fail with 401. Why?
Permission checks and session checks are separate. A 401 on the message endpoint means the X-Session-Token header is missing or does not match the interview. Send the exact session_token from the start response.
Do extra permissions cost anything?
No. Permissions only gate endpoints. Usage is governed by interview credits on the study owner's account, not by key scopes.
Related Articles
Airtable + Koji: Launch AI Interviews from a Base and Sync Every Insight Back to the Record
Turn any Airtable base into a customer research engine: trigger Koji AI-moderated interviews from a view or automation, then write themes, sentiment, quality scores, and a transcript link straight back onto the matching record. No native connector required — Airtable speaks Zapier, Make, and webhooks, and Koji speaks all three.
Amplitude + Koji: Trigger AI Interviews from Product Analytics and Pipe Insights Back as Events
How to close the loop between Amplitude product analytics and Koji AI interviews — fire interview links to users in specific Amplitude cohorts, and pipe interview themes, sentiment, and quality scores back into Amplitude as user properties and custom events.
API Authentication
How Koji Headless API authentication works: pk_live_ API keys, permissions, session tokens, and origin allowlists.
Attio + Koji: Launch AI Interviews from Your CRM and Sync Every Insight Back to the Record
Connect Attio to Koji to trigger AI customer interviews from CRM records and lists, then write themes, quotes, and structured scores back onto each contact and company automatically.
Building with AI: the Koji API for LLMs and coding assistants
A complete, copy-paste starting point for building Koji integrations with an AI coding assistant, plus the MCP server for agentic workflows.
Calendly + Koji: Auto-Run AI Interviews After Every Demo, Call, and No-Show
Connect Calendly to Koji to trigger AI voice and text interviews from meeting events — post-demo, post-onboarding, and no-show follow-ups — and capture structured feedback automatically.