API Authentication
How Koji Headless API authentication works: pk_live_ API keys, permissions, session tokens, and origin allowlists.
API Authentication
Every request to the Koji Headless API authenticates with an API key scoped to a single study. The key both identifies the study and controls what the caller may do, which is why you never send a project id to the interview endpoints. This guide covers the key format, where keys come from, the permission model, session tokens, origin allowlists, and how to keep all of it safe.
How authentication works
Send your key in the Authorization header with the Bearer scheme:
Authorization: Bearer pk_live_wJalrXUtnFEMI4K7MDENGbPxRfiCYz2K
A complete authenticated request looks like this:
curl -X POST https://www.koji.so/api/v1/interviews/start \
-H "Authorization: Bearer pk_live_wJalrXUtnFEMI4K7MDENGbPxRfiCYz2K" \
-H "Content-Type: application/json" \
-d '{
"respondent": { "external_id": "user_8271", "display_name": "Jamie" },
"mode": "text"
}'
Two credentials are involved in a full interview session:
- The API key (
pk_live_...) is your developer credential. It identifies the study and carries the permissions that gate each endpoint. - The session token is a per-interview respondent credential. The start endpoint issues it, and the message and complete endpoints require it in the
X-Session-Tokenheader.
Here is what each endpoint expects:
| 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 |
Key format
pk_live_ followed by 32 URL-safe base64 characters. Keys are stored hashed. The full key is shown exactly once, at creation.
Two practical consequences:
- Copy the key when the create dialog shows it. There is no way to view it again later.
- Because only a hash is stored, keys cannot be read out of Koji's database. If a key leaks from your side, revoke it and create a new one.
Creating a key
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.
For rotating, revoking, and auditing keys, see Managing API Keys.
Permissions
Each key carries a permission set that is checked on every request:
| 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} |
A key missing the required permission gets a 403 with a body like:
{
"error": "API key does not have interview:start permission"
}
Least-privilege setups and the full permission model are covered in API Key Permissions.
Session tokens
- 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 start endpoint returns the token as session_token in its 201 response. See Starting Interviews via API for the full response shape.
Origin allowlists
- Each key has an optional list of allowed origins, checked against the browser's Origin header.
- An empty list allows all origins.
- Requests without an Origin header (curl, server-to-server) always pass the origin check. Origin allowlists protect against browser-based misuse, not server callers.
- Exact entries match the full origin including scheme, e.g.
https://app.example.com. - Wildcard entries like
*.example.commatch the hostname of any subdomain plus the apex domain (any port). Lookalike domains such asevil-example.comdo not match. - A
*entry allows all origins explicitly.
Security best practices
- Keep keys on your server whenever you can. Server-to-server calls are the safest way to use the API.
- If a key must ship to the browser (for example as the embed widget's
api_keyparameter), create a dedicated key with only the permissions that flow needs, and set an origin allowlist so other sites cannot reuse it. - Give read access (
interview:read) only to server-side keys. Transcripts and analysis do not belong in the browser. - Treat each
session_tokenas a secret for its interview. Do not log it, and never share it between respondents. - Revoke keys you no longer use. A revoked key fails with
Invalid API keyon the next request.
Plans and credits
The headless API is available on all plans. Usage is governed by interview credits: each interview consumes credits from the study owner's balance (text and voice at different rates), and the start endpoint rejects new interviews when the study is out of quota or the owner has no credits.
FAQ
Can one key work across multiple studies?
No. Keys are scoped to a single study. The key determines which study an interview belongs to, which is why the start endpoint takes no project id. Create one key per study.
I lost my key. Can I recover it?
No. Keys are stored hashed and shown in full exactly once, at creation. Create a new key and revoke the old one.
Do server-to-server calls need an origin allowlist?
No. Requests without an Origin header, such as curl or backend calls, always pass the origin check. Origin allowlists protect against browser-based misuse, not server callers.
Is the session token a second API key?
No. The API key is your developer credential and works across all endpoints for its study. The session token is issued per interview and only proves that a message or complete request belongs to that respondent's session. The read endpoint does not use it at all.
Related Articles
Headless API Overview
Manage interviews programmatically with the Koji REST API — start, message, and complete interviews from your own code.
Managing API Keys
Create, configure, and revoke project-level API keys for integrating with the Koji API.
Rate Limits and CORS
Per-key rate limits, X-RateLimit headers, 429 handling with backoff, quota errors, and how CORS works on the Koji API.
Research Automation: How to Build Real-Time Research Pipelines with Webhooks
Build automated research pipelines on the Koji API today: event-triggered interviews, completion detection, and insight routing, no native webhooks required.
Starting Interviews via API
Create interview sessions programmatically with POST /interviews/start: request fields, the 201 response, CRM linking, and voice mode.
User Research API: Embed AI Interviews into Any Product or Workflow
How to use Koji's User Research API to run AI-moderated interviews from your own backend. Covers REST endpoints, the embed widget, webhooks, authentication, rate limits, and headless interview patterns.