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
| Pattern | Where it runs | Best for |
|---|---|---|
| Poll the read endpoint | Your server | Reliable completion detection and analysis retrieval |
| Forward the embed completed event | The respondent's browser | Instant in-page reactions when you use the embed widget |
| Automation platforms | Zapier, n8n, Make | No-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:
- When you call
POST /interviews/start, store the returnedinterview_id(plus your ownexternal_id) in a pending table. - A scheduled job fetches each pending id every minute.
- When
statusiscompletedandanalysisis present, run your handler and remove the id from the table. - 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:
analysisis populated only after the interview is completed and the background analysis has finished; otherwise it isnull. Waiting forstatus === 'completed' && analysisgives you the fully processed result in one pass.- The key needs the
interview:readpermission 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:
- A schedule trigger runs every few minutes.
- An HTTP step calls
GET https://www.koji.so/api/v1/interviews/{id}for each pending id with yourAuthorization: Bearerheader. - A filter passes only interviews where
statusiscompletedandanalysisis present. - 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.