Back to docs
API Reference

Webhook Setup

Koji has no native outbound webhooks yet. Three working alternatives: polling the read endpoint, embed completion events, and automation platforms.

Webhook Setup

Let's be direct up front: Koji does not have native outbound webhooks yet. There is no place to register a webhook URL, no signing secret, and no webhook event payloads. Native webhooks are on the roadmap. Until they ship, this guide covers the three patterns that get you the same outcome today, reliably.


What you can build today

PatternWhere it runsBest for
Poll the read endpointYour serverReliable completion detection and analysis retrieval
Forward the embed completed eventThe respondent's browserInstant in-page reactions when you use the embed widget
Automation platformsZapier, n8n, MakeNo-code pipelines on a schedule

Option 1: Poll the read endpoint

The read endpoint returns the interview's status, transcript, stats, and (once ready) the AI analysis:

curl https://www.koji.so/api/v1/interviews/9f4c1e2a-7b3d-4e8f-a1c5-2d6b8e0f4a7c \
  -H "Authorization: Bearer pk_live_wJalrXUtnFEMI4K7MDENGbPxRfiCYz2K"

Returns the full transcript, respondent info, stats, and (once ready) the AI analysis. Server-to-server friendly. No session token required.

The full loop has four steps:

  1. When you call POST /interviews/start, store the returned interview_id (plus your own external_id) in a pending table.
  2. A scheduled job fetches each pending id every minute.
  3. When status is completed and analysis is present, run your handler and remove the id from the table.
  4. Expire ids after a reasonable window so the poller does not grow unbounded.

Step 2 and 3 in code:

// Runs on your server every minute (cron job, worker, or scheduled function).
// pendingIds holds interview ids you stored when you called the start endpoint.
const API_KEY = 'pk_live_wJalrXUtnFEMI4K7MDENGbPxRfiCYz2K'

async function checkPending(pendingIds) {
  for (const id of pendingIds) {
    const res = await fetch(`https://www.koji.so/api/v1/interviews/${id}`, {
      headers: { 'Authorization': `Bearer ${API_KEY}` },
    })
    if (!res.ok) continue

    const interview = await res.json()
    if (interview.status === 'completed' && interview.analysis) {
      await handleCompleted(interview) // your "webhook handler"
      // Remove id from your pending store so it is not processed twice
    }
  }
}

Two details make this robust:

  • analysis is populated only after the interview is completed and the background analysis has finished; otherwise it is null. Waiting for status === 'completed' && analysis gives you the fully processed result in one pass.
  • The key needs the interview:read permission and no session token, so a single server-side key covers the whole worker. See API Key Permissions.

Mind your rate limit: each key allows 60 requests per minute by default, so a poller checking large batches should spread requests or batch by minute. See Rate Limits and CORS.


Option 2: Forward the embed completed event

If your interviews run in the embed widget, the browser already knows the moment an interview finishes. The widget posts this event to the parent page:

{
  "type": "koji:interview_completed",
  "conversationId": "9f4c1e2a-7b3d-4e8f-a1c5-2d6b8e0f4a7c",
  "messageCount": 18
}

The interview finishes (AI-detected or respondent-driven). Does not re-fire when a completed interview is reloaded. Forward it to your backend and you have a webhook-shaped signal:

window.addEventListener('message', (event) => {
  // Always verify the sender before trusting the payload
  if (event.origin !== 'https://www.koji.so') return
  if (event.data?.type !== 'koji:interview_completed') return

  // Forward the completion signal to your own backend
  fetch('/api/koji/interview-completed', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(event.data),
  })
})

Treat this as a fast path, not the source of truth: it only fires while the respondent's tab is open, and it does not re-fire if a completed interview is reloaded. Pair it with Option 1 polling for interviews whose event never arrived. Full event reference in Embed Widget Reference.


Option 3: Automation platforms

Zapier, n8n, and Make can all drive the REST API on a schedule with their generic HTTP modules:

  1. A schedule trigger runs every few minutes.
  2. An HTTP step calls GET https://www.koji.so/api/v1/interviews/{id} for each pending id with your Authorization: Bearer header.
  3. A filter passes only interviews where status is completed and analysis is present.
  4. Downstream steps route the result: Slack message, CRM update, spreadsheet row.

This is Option 1 without writing code. The same rate limit and permission notes apply.


Native webhooks: coming soon

Outbound webhooks are planned. When they ship, they will replace the polling loop, not the rest of your pipeline: keep your completion handling in one function (like handleCompleted above) and the switch will be a one-line change from poller to webhook receiver.


FAQ

Where do I register my webhook URL?

Nowhere yet. Koji has no native outbound webhooks today. Use one of the three patterns above.

How often should I poll?

Every minute is a good default. With the default limit of 60 requests per minute per key, that is up to 60 pending interviews checked per cycle without special handling.

Is the embed event enough on its own?

No. It only fires in an open browser tab and never re-fires for already-completed interviews. Use it for instant UX reactions and keep polling as the source of truth.

Will I need to rebuild when native webhooks ship?

Not if you isolate completion handling in one function. Swap the trigger from your poller to the webhook receiver and keep everything downstream unchanged.

Does polling give me the transcript too, or just the analysis?

Everything. The read endpoint returns the full transcript, respondent info (including your external_id), session stats, and the analysis in a single response, so one fetch feeds every downstream destination.

Related Articles

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.

Completing Interviews via API

Finalize interviews with POST /interviews/{id}/complete, then poll the read endpoint for the asynchronous AI analysis.

Exporting Research Data from Koji: CSV, JSON, and Transcript Access

A complete guide to every way you can get your interview data out of Koji — from one-click CSV downloads to real-time webhook pipelines.

Headless API Overview

Manage interviews programmatically with the Koji REST API — start, message, and complete interviews from your own code.

Sync Koji Customer Interviews to HubSpot: Live Insights on Every Contact

Push Koji interview transcripts, themes, and quality scores onto HubSpot contact and company records in real time using webhooks and the HubSpot API.

Send Koji Insights to Linear: Auto-File Engineering Tickets from Customer Interviews

Wire Koji to Linear so every customer interview that surfaces a real pain point auto-creates a tagged Linear issue — with verbatim quote, theme, study link, and quality score attached. Replace the Slack-thread-to-screenshot-to-ticket workflow with a webhook.

MCP Troubleshooting Guide: Fix Koji MCP Server Connection and Tool Errors

Diagnose and fix the five most common Koji MCP issues: 401 auth errors, network timeouts, missing tools, credit and rate limits, and confirmation-prompt conflicts. Includes a triage table and copy-paste fixes for Claude Desktop, Cursor, VS Code, and Windsurf.

Connect Koji to n8n: Build Self-Hosted Customer Research Pipelines

Wire Koji into n8n via webhooks and the REST API to build self-hosted pipelines that route every completed interview into Notion, Linear, Slack, your CRM, or any other system — without sending data through a third-party automation cloud.

Sync Koji Research Insights to Notion: Build a Self-Updating Research Repository

Connect Koji to Notion via Zapier (or webhook) so every completed AI interview becomes a fresh Notion page — with transcript, structured answers, themes, quality score, and AI summary attached. Build a research repository that updates itself.

How to Build a Continuous Product Feedback Loop

A step-by-step guide to building a durable product feedback loop — using trigger-based AI interviews, structured question trend tracking, and webhook integrations to keep your product decisions grounded in real user experience.

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.

Sync Koji AI Interviews to Salesforce: Customer Insights on Every Account, Contact, and Opportunity

Push interview transcripts, AI themes, sentiment, and quality scores from Koji into Salesforce in real time using webhooks and the Salesforce REST API — so account executives, customer success managers, and revenue ops teams act on customer evidence inside the CRM they already live in.

Send Research Insights to Slack: Real-Time Customer Interview Notifications via Webhooks

Pipe customer interview insights from Koji into your Slack workspace in real time. Use Koji webhooks to notify a #research channel the moment an interview completes, post quote highlights to #product-feedback, or alert #cs-alerts when a churn signal is detected. Step-by-step setup with a working Slack incoming webhook recipe.

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.

Connect Koji to Zapier: Automate Customer Research Workflows in Minutes

Route every completed AI customer interview from Koji into 6,000+ Zapier apps — including Notion, Linear, Salesforce, Airtable, and Gmail. A step-by-step integration guide.