New

Now in Claude, ChatGPT, Cursor & more with our MCP server

Back to docs
API Reference

Starting Interviews via API

Use the POST /start endpoint to programmatically launch interviews from your application.

Starting Interviews via API

The POST /api/v1/interviews/start endpoint lets you programmatically launch an interview session from your own application. This is the entry point for any headless integration with Koji.


Before You Begin

Make sure you have:

  • An API key with the interview:start permission. See API Authentication for how to create one.
  • A project with a published research brief.
  • API access is available on all Koji plans, including the free tier.

Endpoint

POST https://koji.so/api/v1/interviews/start

Headers

HeaderValueRequired
AuthorizationBearer your_api_keyYes
Content-Typeapplication/jsonYes

Request Body

Send a JSON object with the following fields:

FieldTypeRequiredDescription
respondentobjectNoRespondent information (see below)
modestringNoInterview mode: text or voice. Defaults to the project setting
localestringNoLanguage/locale code (e.g., en, es, fr). Defaults to the project setting

Respondent Object

The respondent field accepts an object with these properties:

FieldTypeRequiredDescription
external_idstringNoYour own identifier for this respondent, useful for linking back to your system
display_namestringNoDisplay name for the respondent
metadataobjectNoArbitrary key-value pairs attached to the respondent for your own tracking purposes

Note that metadata is nested under the respondent object, not at the top level of the request body.

Example Request

curl -X POST https://koji.so/api/v1/interviews/start \
  -H "Authorization: Bearer pk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{'
    "respondent": {
      "external_id": "user_12345",
      "display_name": "Jane Doe",
      "metadata": {
        "segment": "power_users",
        "source": "onboarding_flow"
      }
    },
    "mode": "text",
    "locale": "en"
  }'

Response

A successful request returns a 201 Created response with a JSON body:

{
  "interview_id": "f8e7d6c5-b4a3-2109-8765-432109876543",
  "session_token": "st_live_xxxxxxxxxxxxxxxxxxxx",
  "initial_message": "Hi Jane! Thanks for taking the time to chat with us today. I'd love to learn about your experience..."
}

Response Fields

FieldTypeDescription
interview_idstringUnique identifier for this interview. Use this for all subsequent API calls.
session_tokenstringToken required for session-scoped operations like sending messages and completing the interview. Pass it as X-Session-Token header.
initial_messagestringThe first message from the interviewer. Display this to the respondent.

Store the interview_id and session_token — you need both for subsequent operations.

Important: The response field is interview_id, not conversation_id. Use interview_id consistently across all API calls.


Structured Questions

If your research brief includes structured questions (scale ratings, multiple choice, ranking, yes/no), the interview will present interactive widgets to the respondent during the conversation. When the interview completes and analysis runs, structured answers are returned alongside qualitative insights.

Each structured answer in the analysis includes:

  • questionId and questionText — identifies which question was answered
  • questionType — the type of question (scale, single_choice, multiple_choice, ranking, yes_no)
  • structuredValue — the typed response (number for scale, string for single choice, string array for multiple choice or ranking, boolean for yes/no)
  • qualitativeAnswer — any additional context the respondent provided
  • confidence — how confident the analysis is in the extracted answer
  • followUpInsights — insights from follow-up probing

This enables programmatic aggregation of quantitative data alongside qualitative insights.


Understanding the Response

interview_id

This is your primary reference for the interview. Use it to send messages, complete it, and look it up in your project dashboard.

session_token

The session token acts as a secondary authentication layer scoped to this specific interview. It proves that the caller is the same entity that started the interview. You must include it when calling the message endpoint and the complete endpoint.

initial_message

This is the greeting generated for the respondent based on your research brief, project settings, and any respondent information you provided. Display this message in your interface as the start of the conversation.


Handling Errors

Status CodeErrorMeaning
400invalid_requestMissing required fields or invalid field values
401unauthorizedInvalid or missing API key
403forbiddenKey lacks interview:start permission
404not_foundThe specified project does not exist
422unprocessableThe project has no published brief, or configuration prevents starting
429rate_limitedToo many requests. Check Rate Limits and CORS

All error responses include a JSON body with error and message fields:

{
  "error": "invalid_request",
  "message": "The project has no published research brief."
}

Respondent Metadata

The metadata field inside the respondent object accepts any flat JSON object. Use it to attach your own tracking data to the respondent. Common use cases include:

  • User segmentation: {"plan": "enterprise", "tenure_months": 24}
  • Source tracking: {"source": "post_purchase_email", "campaign_id": "camp_123"}
  • A/B testing: {"variant": "B", "experiment": "onboarding_v2"}

Metadata is returned when you retrieve the interview and is available in exports and webhooks. It does not affect the interview itself.


Integration Patterns

Server-to-Server

The most common pattern is calling the start endpoint from your backend when a user triggers an action (for example, clicking a "Give Feedback" button). Your backend starts the interview, receives the response, and passes the interview_id and initial_message to your frontend.

Batch Invitations

For research projects, you might start interviews in batch — for example, iterating through a list of participants and starting an interview for each one. Store the returned interview_id and session_token for each participant so you can track and complete them later.

Embedded Experience

Combine the API with the embed widget for a hybrid approach: start the interview server-side for tracking purposes, then hand off the interview_id to the embed widget for the conversational UI.


Next Steps

Further reading on the blog

<!-- further-reading:blog -->