{"site":{"name":"Koji","description":"AI-native customer research platform that helps teams conduct, analyze, and synthesize customer interviews at scale.","url":"https://www.koji.so","contentTypes":["blog","documentation"],"lastUpdated":"2026-05-18T13:47:09.815Z"},"content":[{"type":"documentation","id":"326ce594-92b4-48ba-a543-8a9f7a506611","slug":"completing-interviews-via-api","title":"Completing Interviews via API","url":"https://www.koji.so/docs/completing-interviews-via-api","summary":"Complete interviews via POST /api/interview/complete to trigger automatic analysis. The analysis pipeline extracts themes, insights, quality scores, and structured answers (scale ratings, choices, rankings). Results are retrievable via GET /api/v1/interviews/:id once analysis finishes. Supports webhook notifications and polling.","content":"# Completing Interviews via API\n\nMarking an interview as complete triggers Koji's automatic analysis pipeline, which extracts themes, insights, structured answers, and quality scores from the conversation. This is the final step in the API interview lifecycle.\n\n---\n\n## When to Complete an Interview\n\nThere are several scenarios where you should complete an interview:\n\n- **The respondent finishes naturally.** The interview status changes to indicate the conversation has reached its conclusion. Your application should detect this and call complete.\n- **The respondent leaves early.** If the respondent closes their browser or navigates away, complete the interview so that whatever data was collected gets analyzed.\n- **You want to end it manually.** For testing or operational reasons, you might need to end an interview before the conversation naturally concludes.\n- **A timeout is reached.** If your application enforces a maximum interview duration, call complete when the timer expires.\n\nCompleting an interview is idempotent — calling it on an already-completed interview returns the same response without re-triggering analysis.\n\n---\n\n## Endpoint\n\n```\nPOST https://koji.so/api/interview/complete\n```\n\n### Headers\n\n| Header | Value | Required |\n|---|---|---|\n| `Authorization` | `Bearer your_api_key` | Yes |\n| `X-Session-Token` | `session_token_from_start` | Yes |\n| `Content-Type` | `application/json` | Yes |\n\nBoth the API key and the session token are required. The API key authenticates your application, and the session token verifies that you are the same entity that started this specific interview. See [API Authentication](/docs/api-authentication) for details on both.\n\n### Request Body\n\nThe request body should include the interview identifier:\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `interview_id` | string | Yes | The interview ID returned from the start endpoint |\n| `reason` | string | No | Why the interview ended. Options: `natural`, `respondent_left`, `timeout`, `manual`. Defaults to `manual`. |\n\n### Example Request\n\n```bash\ncurl -X POST https://koji.so/api/interview/complete \\\n  -H \"Authorization: Bearer pk_live_your_key_here\" \\\n  -H \"X-Session-Token: st_live_xxxxxxxxxxxxxxxxxxxx\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{'\n    \"interview_id\": \"f8e7d6c5-b4a3-2109-8765-432109876543\",\n    \"reason\": \"natural\"\n  }'\n```\n\n---\n\n## Response\n\nA successful request returns `200 OK` with a summary of the completed interview:\n\n```json\n{\n  \"interview_id\": \"f8e7d6c5-b4a3-2109-8765-432109876543\",\n  \"status\": \"completed\",\n  \"completed_at\": \"2025-01-15T10:25:30Z\",\n  \"analysis_status\": \"processing\",\n  \"stats\": {\n    \"duration_seconds\": 1530,\n    \"respondent_messages\": 18,\n    \"interviewer_messages\": 19,\n    \"total_messages\": 37\n  }\n}\n```\n\n### Response Fields\n\n| Field | Type | Description |\n|---|---|---|\n| `interview_id` | string | The interview identifier |\n| `status` | string | Always `completed` on success |\n| `completed_at` | string (ISO 8601) | Timestamp when the interview was marked complete |\n| `analysis_status` | string | Status of the automatic analysis: `processing`, `completed`, or `failed` |\n| `stats` | object | Summary statistics for the interview |\n\n---\n\n## What Happens After Completion\n\nCompleting an interview triggers several automatic processes:\n\n1. **Transcript finalization.** The full conversation is finalized and stored.\n2. **Quality scoring.** Koji evaluates the interview quality based on the depth of responses, topic coverage, and respondent engagement.\n3. **Automatic analysis.** Koji's analysis engine processes the transcript, extracting themes, insights, and patterns.\n4. **Structured answer extraction.** If the interview used [structured questions](/docs/structured-questions-guide), the analysis extracts typed answers (scale ratings, choices, rankings, yes/no responses) alongside qualitative context.\n5. **Webhook delivery.** If you have [webhooks configured](/docs/webhook-setup), Koji sends an event notification when analysis completes.\n\nAnalysis typically takes a few seconds to a couple of minutes, depending on the interview length. Poll the interview endpoint or use webhooks to know when results are ready.\n\n---\n\n## Retrieving Results After Completion\n\nOnce `analysis_status` is `completed`, retrieve the full results:\n\n```\nGET https://koji.so/api/v1/interviews/:interview_id\n```\n\nThe response now includes the analysis payload alongside the transcript:\n\n```json\n{\n  \"interview_id\": \"f8e7d6c5-b4a3-2109-8765-432109876543\",\n  \"status\": \"completed\",\n  \"transcript\": [...],\n  \"analysis\": {\n    \"themes\": [...],\n    \"insights\": [...],\n    \"quality_score\": 4.2,\n    \"structured_answers\": [\n      {\n        \"questionId\": \"q_1\",\n        \"questionText\": \"How likely are you to recommend us?\",\n        \"questionType\": \"scale\",\n        \"structuredValue\": 8,\n        \"qualitativeAnswer\": \"Very likely, the product has been transformative.\",\n        \"confidence\": \"high\",\n        \"followUpInsights\": [\"Values the onboarding experience\"]\n      }\n    ]\n  },\n  \"stats\": {\n    \"duration_seconds\": 1530,\n    \"respondent_messages\": 18,\n    \"interviewer_messages\": 19\n  }\n}\n```\n\nThe `structured_answers` array is present when the interview used structured questions. Each entry contains the typed value alongside qualitative context, enabling programmatic aggregation of quantitative data.\n\n---\n\n## Polling for Analysis Completion\n\nIf you do not use webhooks, poll the interview endpoint to check when analysis finishes:\n\n```javascript\nasync function waitForAnalysis(interviewId, apiKey) {\n  const maxAttempts = 30;\n  const delayMs = 2000;\n\n  for (let i = 0; i < maxAttempts; i++) {\n    const response = await fetch(\n      `https://koji.so/api/v1/interviews/${interviewId}`,\n      { headers: { 'Authorization': `Bearer ${apiKey}` } }\n    );\n    const data = await response.json();\n\n    if (data.analysis_status === 'completed') {\n      return data;\n    }\n\n    if (data.analysis_status === 'failed') {\n      throw new Error('Analysis failed');\n    }\n\n    await new Promise(resolve => setTimeout(resolve, delayMs));\n  }\n\n  throw new Error('Analysis timed out');\n}\n```\n\nStart with a 2-second interval and increase it if analysis takes longer. Most interviews complete analysis within 30 seconds.\n\n---\n\n## Error Handling\n\n| Status Code | Error | Meaning |\n|---|---|---|\n| 401 | `unauthorized` | Invalid API key or session token |\n| 403 | `forbidden` | Key lacks `interview:complete` permission |\n| 404 | `not_found` | Interview does not exist |\n| 409 | `already_completed` | Interview was already completed (response still returns the interview data) |\n| 429 | `rate_limited` | Too many requests |\n\nThe 409 response is not an error in the traditional sense — it simply tells you the interview was already finished. The response body contains the same data as a successful completion.\n\n---\n\n## Session Token Requirement\n\nThe `X-Session-Token` header is mandatory for the complete endpoint. This prevents unauthorized parties who might have your API key from completing interviews they did not start.\n\nIf you have lost the session token, the interview can still be completed from the Koji dashboard by a team member with appropriate access.\n\n---\n\n## Next Steps\n\n- [Set up webhooks to be notified when analysis completes](/docs/webhook-setup)\n- [Review the authentication model](/docs/api-authentication)\n- [Start your integration with the start endpoint](/docs/starting-interviews-via-api)\n- [Learn about structured questions](/docs/structured-questions-guide)\n- [Explore the headless API overview](/docs/headless-api-overview)\n\n## Further reading on the blog\n\n- [How to Analyze User Interview Data: A Complete Guide (2026)](/blog/how-to-analyze-user-interview-data) — You ran the interviews. Now what? This step-by-step guide covers how to turn raw interview data into clear, actionable insights — with and w\n\n<!-- further-reading:blog -->\n","category":"API Reference","lastModified":"2026-05-13T00:25:38.788654+00:00","metaTitle":"Completing Interviews via API — Koji Docs","metaDescription":"Mark interviews as complete and trigger automatic analysis using the Koji API POST /complete endpoint.","keywords":["complete interview","api complete","interview analysis","session token","post complete"],"aiSummary":"Complete interviews via POST /api/interview/complete to trigger automatic analysis. The analysis pipeline extracts themes, insights, quality scores, and structured answers (scale ratings, choices, rankings). Results are retrievable via GET /api/v1/interviews/:id once analysis finishes. Supports webhook notifications and polling.","aiPrerequisites":["starting-interviews-via-api","api-authentication"],"aiLearningOutcomes":["Complete interviews via the API","Understand the automatic analysis pipeline","Poll for or receive analysis results","Handle completion errors and edge cases"],"aiDifficulty":"intermediate","aiEstimatedTime":"7 min read"}],"pagination":{"total":1,"returned":1,"offset":0}}