API Reference

Base URL: https://usertold.ai

Exact endpoint schemas are generated from the shipped contracts. Fetch the full OpenAPI 3.1 spec at /api/openapi — use this page for the stable integration map and the generated document for request/response details.

Authentication

Three auth methods depending on the endpoint:

MethodHeaderUsed By
JWTAuthorization: Bearer <token> or auth_token cookieDashboard
SDK KeyX-Project-Key: ut_pub_... or ?key=ut_pub_...Embedded widget
WebhookHMAC signature verificationGitHub, Polar webhooks

Error Format

{
  "code": "OPTIONAL_CODE",
  "retryable": false,
  "message": "Description of what went wrong",
  "action": "Optional next step for user"
}

Common status codes: 400 validation, 401 auth required, 402 payment required, 403 forbidden, 404 not found, 429 rate limited.

Project-scoped routes use canonical handles in the path:

  • frontend route params: :org and :project (for /o/:org/p/:project/...)
  • API path params remain :orgHandle and :projectHandle

Scoped resolver support:

  • :studyId accepts study id or handle (within project scope)
  • :screenerId accepts intake id or handle (within project scope)

MCP for Agentic Workflows

Use MCP when your agents need discovery and project-aware execution in one protocol surface.

  • Endpoint: POST /mcp
  • Auth: OAuth 2.1 for remote MCP clients (Authorization Code + PKCE). MCP accepts bearer tokens after OAuth issuance.
  • Methods: initialize, initialized, tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/templates/list, resources/read
  • Discovery: GET /.well-known/openid-configuration, GET /.well-known/oauth-protected-resource
  • Dynamic client registration: supported via POST /api/oauth/register (RFC 7591). Management endpoints: GET/PUT/DELETE /api/oauth/register/:clientId. Static allowlist clients are also supported for pre-registered integrations.

Initialize:

{
  "jsonrpc": "2.0",
  "id": "init-1",
  "method": "initialize",
  "params": { "protocolVersion": "2025-11-25", "capabilities": { "tools": {}, "prompts": {}, "resources": {} } }
}

Call a tool:

{
  "jsonrpc": "2.0",
  "id": "tools-1",
  "method": "tools/call",
  "params": {
    "name": "work.list",
    "arguments": { "projectRef": "prj_..." }
  }
}

For non-agent automation workflows, continue using the REST routes in this doc.


Health

GET /api/health

Public. Returns service status.

{ "status": "ok", "environment": "production" }

Auth

Google is the primary identity provider. GitHub and Linear OAuth flows are used to connect those integrations for delivery tracker handoff, not to sign users in.

GET /api/auth/session

Returns the current session payload (user, org membership). Used by the dashboard on bootstrap.

GET /api/auth/google/login

Start the Google OAuth flow. Redirects the browser to Google. Rate limited: 10 req/min per IP.

GET /api/auth/google/callback

Google OAuth callback. Exchanges the authorization code for a session and sets an HTTP-only auth_token cookie.

GET /api/auth/github/login

Start the GitHub OAuth flow (used to link a GitHub identity to an existing account, not as a primary sign-in).

GET /api/auth/github/callback

GitHub OAuth callback.

GET /api/auth/linear/login

Start the Linear OAuth flow (links Linear identity). For installing the Linear delivery integration, see Integrations → Linear.

GET /api/auth/linear/callback

Linear OAuth callback.

POST /api/auth/logout

Clear session.

POST /api/auth/onboarding

Complete first-run onboarding (records org handle preferences and product-tour state).

POST /api/auth/sessions/revoke-older

Revoke every active session for the current user except the calling one.

GET /api/user/profile

Auth: JWT. Returns current user profile, including personal_org_handle.

PATCH /api/user/profile

Auth: JWT. Update user name.


Projects

Canonical project metadata fields on project-bearing responses:

  • organization_id
  • org_handle
  • project_handle
  • project_ref (org/project)
  • canonical_path (/o/:org/p/:project)

GET /api/orgs/:orgHandle/projects

Auth: JWT. List all projects for the authenticated user.

POST /api/orgs/:orgHandle/projects

Auth: JWT. Create a project.

{ "name": "My Product", "description": "optional", "github_repo_url": "owner/repo" }

GET /api/orgs/:orgHandle/projects/:projectHandle

Auth: JWT. Get project details and members.

PATCH /api/orgs/:orgHandle/projects/:projectHandle

Auth: JWT (owner/admin). Update project fields.

DELETE /api/orgs/:orgHandle/projects/:projectHandle

Auth: JWT (owner only). Delete project.


Interviews

All interview routes require JWT + Project membership.

GET /api/orgs/:orgHandle/projects/:projectHandle/sessions

List interviews. Query params: status, processing_status, limit, offset.

POST /api/orgs/:orgHandle/projects/:projectHandle/sessions

Create an interview. Requires billing check.

{
  "participant_name": "Jane",
  "participant_email": "jane@example.com",
  "interview_mode": "voice",
  "screener_id": "scr_...",
  "screener_response_id": "resp_..."
}

POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/upload-video

Upload multipart form data with either media (audio or video, max 25 MB) or separate audio (max 25 MB) plus optional video (max 100 MB), optional participant_name, optional participant_email, and optional active study_id. The legacy single video field is still accepted when audio is absent. Creates an async interview, stores audio as transcription media, stores optional video as playback media, and queues the standard interview processing pipeline.

POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/import-transcript

Upload multipart form data with transcript (text, max 5 MiB), optional participant_name, optional participant_email, and optional active study_id. Creates a transcript-only async interview, stores the transcript artifact, and queues the standard evidence extraction pipeline.

GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId

Get an interview with messages, events, and audio chunks.

PATCH /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId

Update interview fields (status, summary, consent flags).

POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/reprocess

Reprocess a completed interview (re-run evidence extraction). Manual evidence is preserved by default; pass replace_manual_evidence=true only when the manual evidence should be discarded and replaced by the rerun.

DELETE /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId

Delete an interview.


Evidence

All evidence routes require JWT + Project membership.

GET /api/orgs/:orgHandle/projects/:projectHandle/signals

List evidence. Query params: type, session_id, task_id, search, min_confidence, dismissed, limit, offset.

GET /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId

Get evidence card details.

PATCH /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId

Update evidence fields (type, confidence, quote, analysis, context).

POST /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId/annotate

Add human annotation. Body: { "text": "..." } (max 2000 chars).

POST /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId/dismiss

Soft-exclude an evidence card. Body: { "reason": "..." }.

POST /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId/undismiss

Restore a dismissed evidence card.

POST /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId/link

Link an evidence card to a work item. Body: { "task_id": "..." }.

POST /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId/unlink

Unlink an evidence card from a work item.

DELETE /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId

Delete an evidence card.


Work

All work item routes require JWT + Project membership.

GET /api/orgs/:orgHandle/projects/:projectHandle/tasks

List work items. Query params: status, type, limit, offset.

GET /api/orgs/:orgHandle/projects/:projectHandle/tasks/ready

List high-priority work items ready for implementation. Query params: limit (default 10).

POST /api/orgs/:orgHandle/projects/:projectHandle/tasks

Create a work item.

{
  "title": "Fix checkout abandonment",
  "description": "Users drop off at payment step",
  "task_type": "bug",
  "priority_score": 75,
  "effort_estimate": "m"
}

GET /api/orgs/:orgHandle/projects/:projectHandle/tasks/:taskId

Get a work item with linked evidence.

PATCH /api/orgs/:orgHandle/projects/:projectHandle/tasks/:taskId

Update work item fields. Priority label auto-calculated from score (critical >= 80, high >= 60, medium >= 40, low < 40).

DELETE /api/orgs/:orgHandle/projects/:projectHandle/tasks/:taskId

Delete a work item.


Intake

Dashboard Routes (JWT + Project)

GET /api/orgs/:orgHandle/projects/:projectHandle/screeners — List intakes.

POST /api/orgs/:orgHandle/projects/:projectHandle/screeners — Create an intake with optional inline questions.

{
  "title": "Beta User Study",
  "welcome_message": "Help us improve!",
  "brand_color": "#3b82f6",
  "consent_text": "I agree to participate",
  "max_participants": 50,
  "questions": [
    {
      "question_text": "How often do you use our product?",
      "question_type": "single_choice",
      "options": ["Daily", "Weekly", "Monthly", "Rarely"],
      "qualification_rules": { "qualify": ["Daily", "Weekly"] }
    }
  ]
}

GET /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId — Get an intake with questions and responses.

PATCH /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId — Update intake fields.

DELETE /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId — Delete an intake.

POST /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId/questions — Add a question.

PATCH /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId/questions/:questionId — Update a question.

DELETE /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId/questions/:questionId — Delete a question.

POST /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId/questions/reorder — Reorder questions. Body: { "question_ids": ["q1", "q2", "q3"] }.

Public SDK Routes (SDK Key)

GET /api/sdk/screeners — List active intakes for the project. Rate limited: 30 req/min.

GET /api/sdk/screener/:screenerId — Get an intake with questions (public fields only). Rate limited: 60 req/min.

POST /api/sdk/screener/:screenerId/respond — Submit intake response. Rate limited: 10 req/min.

{
  "answers": { "q1": "Daily", "q2": "Developer" },
  "consent_given": true,
  "consent_recording": true,
  "participant_name": "Jane",
  "participant_email": "jane@example.com"
}

Studies

Dashboard Routes (JWT + Project)

GET /api/orgs/:orgHandle/projects/:projectHandle/studies — List studies.

POST /api/orgs/:orgHandle/projects/:projectHandle/studies — Create a study.

{
  "title": "Checkout Research",
  "goals": [{ "id": "g1", "description": "Find checkout friction" }],
  "script": {
    "version": 2,
    "goals": [{ "id": "g1", "description": "Find checkout friction" }],
    "segments": [
      { "id": "intro", "mode": "speak", "title": "Instructions", "speak_text": "Please complete checkout and think aloud as you go." },
      { "id": "task", "mode": "observe", "title": "Complete checkout", "instruction": "Complete checkout from cart to confirmation.", "conductor_context": "Capture checkout hesitation, errors, page paths, and recovery behavior for the debrief." },
      { "id": "debrief", "mode": "talk", "title": "Discuss" },
      { "id": "thanks", "mode": "speak", "title": "Thanks", "speak_text": "Thanks for completing the interview." }
    ]
  }
}

GET /api/orgs/:orgHandle/projects/:projectHandle/studies/:studyId — Get study details.

PATCH /api/orgs/:orgHandle/projects/:projectHandle/studies/:studyId — Update study.

DELETE /api/orgs/:orgHandle/projects/:projectHandle/studies/:studyId — Delete study.

Public SDK Route

GET /api/sdk/study/:studyId — Get active study with parsed script and settings.


Conductor (Interview Runtime)

SDK Key auth. These power the real-time interview experience.

POST /api/sdk/conductor/:sessionId/start

Initialize the conductor interview. Returns the WebSocket URL, preserving the caller's compatibility session_token when one was supplied to start. Rate limited: 10 req/min.

{ "ws_url": "wss://app.usertold.ai/api/sdk/conductor/ses_.../ws?key=ut_pub_...&session_token=compat_..." }

POST /api/sdk/conductor/:sessionId/checkpoint

Best-effort unload checkpoint for pagehide / beforeunload. Persists the current conductor snapshot and arms disconnect finalization if the participant does not reconnect.

GET /api/sdk/conductor/:sessionId/ws

WebSocket upgrade endpoint for real-time interview orchestration.

POST /api/sdk/conductor/:sessionId/transcription-secret

Get ephemeral token for browser-side speech transcription. Rate limited: 5 req/min.

POST /api/sdk/conductor/:sessionId/sts-secret

Get ephemeral token for browser-side voice conversation. Rate limited: 5 req/min.

POST /api/sdk/conductor/:sessionId/realtime-call

Create a browser WebRTC Realtime call through the server path. Body:

{ "sdp": "v=0..." }

Returns an SDP answer plus call metadata:

{
  "sdp": "v=0...",
  "call_id": "call_...",
  "model": "gpt-realtime-...",
  "reasoning_enabled": true,
  "sideband_enabled": true
}

This endpoint is available only after the conductor interview has started and is in talk mode. See /api/openapi for exact schemas.

POST /api/sdk/conductor/:sessionId/end

End the conductor interview. Idempotent. Queues the interview for processing.


SDK Utilities

POST /api/sdk/sessions

Create an interview without an intake. Rate limited: 20 req/min.

Optional body fields:

  • study_id: start a direct study interview and bind the interview to that active study

POST /api/sdk/audio/upload

Upload audio chunk (FormData). Max 10 MB per chunk. Rate limited: 30 req/min per interview.

POST /api/sdk/screen/upload-session/start

Start a screen recording upload session. Body:

{ "session_id": "ses_..." }

Returns:

{ "upload_session_id": "upl_..." }

POST /api/sdk/screen/upload-session/upload-part

Upload one screen recording part. Send a binary body with headers:

  • X-Project-Key: ut_pub_...
  • X-Session-Id: ses_...
  • X-Part-Number: 1
  • Content-Type: application/octet-stream

Returns:

{ "part_number": 1, "etag": "..." }

POST /api/sdk/screen/upload-session/finalize

Finalize the screen recording upload session. Body:

{ "session_id": "ses_..." }

Returns:

{ "r2_key": "..." }

For exact SDK route schemas, use /api/openapi.

POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/events

Append an interview event to an existing interview.

{
  "event_type": "click",
  "timestamp_ms": 1707000000000,
  "event_line": "Clicked checkout button",
  "data": { "selector": ".btn" }
}

Billing

GET /api/billing

Auth: JWT. Get billing status (payment status, spending cap, usage).

GET /api/billing/events

Auth: JWT. Paginated billing event history (charges, credit grants, failures). Query params: limit (default 50, max 100), offset.

POST /api/billing/checkout

Auth: JWT. Create payment checkout session.


Webhooks

POST /api/webhooks/github

GitHub App webhook receiver. Verified via HMAC-SHA256 (X-Hub-Signature-256). Handles issue state changes that sync back onto linked work items (and trigger evidence resolution when an issue closes).

POST /api/webhooks/linear

Linear webhook receiver. Verified via HMAC-SHA256 (linear-signature) and timestamp window to reject replays. Handles Issue and Comment resource events; an issue moving into a completed-status workflow state resolves the current linked evidence on the matching work item.

The webhook is registered automatically when an org connects Linear (see Integrations → Linear).

POST /api/webhooks/polar

Polar.sh webhook receiver. Verified via HMAC-SHA256. Handles payment and credit events.


Integrations

These endpoints connect a delivery tracker to an org or project. The flows are normally driven from the dashboard, but the routes are stable.

Linear

MethodPathPurpose
GET/api/orgs/:orgHandle/linear/connectStart Linear OAuth flow for the org.
GET/api/orgs/:orgHandle/linear/claimClaim a Linear webhook registration during a concurrent connect.
GET/api/linear/callbackLinear OAuth callback. Completes the connection and registers the webhook.
GET/api/orgs/:orgHandle/linear/connectionGet connection status.
DELETE/api/orgs/:orgHandle/linear/connectionDisconnect Linear from this org.
GET/api/orgs/:orgHandle/linear/webhook/statusCheck whether the webhook registration is healthy.
GET/api/orgs/:orgHandle/projects/:projectHandle/linear/teamsList Linear teams the connected workspace can post to.
POST/api/orgs/:orgHandle/projects/:projectHandle/linear/select-teamChoose the Linear team that receives pushed work items.
POST/api/orgs/:orgHandle/projects/:projectHandle/tasks/:taskId/push/linearLinear-only alias for POST .../tasks/:taskId/push.

GitHub App

The GitHub integration uses the GitHub App flow, not OAuth-as-login. Installations are scoped per project.

MethodPathPurpose
GET/api/orgs/:orgHandle/projects/:projectHandle/github-app/installBegin GitHub App installation for this project.
GET/api/github/app/setupGitHub App post-install setup callback.
GET/api/orgs/:orgHandle/projects/:projectHandle/github-app/installationsList installations the user can attach.
POST/api/orgs/:orgHandle/projects/:projectHandle/github-app/select-installationAttach an installation to the project.
GET/api/orgs/:orgHandle/projects/:projectHandle/github-app/reposList repos visible to the attached installation.
POST/api/orgs/:orgHandle/projects/:projectHandle/github-app/select-repoBind the project to a specific repo for work item push.

Implementations

Implementation is the term for a configured delivery integration on a project (GitHub or Linear).

MethodPathPurpose
GET/api/orgs/:orgHandle/projects/:projectHandle/implementationsList configured integrations.
GET/api/orgs/:orgHandle/projects/:projectHandle/implementations/:implIdGet integration detail (status, last sync, target).
GET/api/orgs/:orgHandle/projects/:projectHandle/tasks/:taskId/provider-stateGet the latest tracker-side state for a pushed work item (issue URL, state, last sync).

Project Settings

Per-project settings, including BYOK keys.

MethodPathPurpose
GET/api/orgs/:orgHandle/projects/:projectHandle/settingsGet masked project settings (keys are never returned in cleartext).
PATCH/api/orgs/:orgHandle/projects/:projectHandle/settingsUpdate settings (e.g. openai_api_key). Encrypted at rest.
POST/api/orgs/:orgHandle/projects/:projectHandle/settings/validateValidate a candidate value (e.g. test an OpenAI key) before persisting.
GET/api/orgs/:orgHandle/projects/:projectHandle/settings/key-healthPer-key health (last successful call, last error).

OAuth Client Management (RFC 7591)

These routes back dynamic MCP client registration. Most agents never call them directly — see MCP Integration.

MethodPathPurpose
GET/.well-known/openid-configurationOAuth/OIDC discovery document.
GET/.well-known/jwks.jsonPublic JWKS for verifying issued tokens.
GET/.well-known/oauth-protected-resourceRFC 9728 resource metadata (for the MCP server itself).
GET/api/oauth/authorizeAuthorization endpoint.
GET/api/oauth/authorize/requestAuthorization request prep (used by the consent UI).
POST/api/oauth/authorize/decisionRecord the user's consent decision.
GET/api/oauth/callbackOAuth callback.
POST/api/oauth/tokenToken endpoint.
POST/api/oauth/registerDynamic client registration (RFC 7591).
GET/api/oauth/register/:clientIdRead a registered client.
PUT/api/oauth/register/:clientIdUpdate a registered client.
DELETE/api/oauth/register/:clientIdDelete a registered client.

Additional Resource Operations

Endpoints that exist alongside the basics described above:

Evidence

  • POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/signals — create a lightweight, needs-review manual correction scoped to an interview (manual addition from the dashboard).
  • POST /api/orgs/:orgHandle/projects/:projectHandle/signals/:signalId/review — mark an evidence card as reviewed.
  • POST /api/orgs/:orgHandle/projects/:projectHandle/signals/bulk-link — link many evidence cards to one work item in a single call.
  • POST /api/orgs/:orgHandle/projects/:projectHandle/signals/bulk-delete — delete multiple evidence cards at once.

Interviews

  • POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/processing-status — batch processing status for multiple interview IDs.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/processing — single-interview processing status.
  • POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/retry-transcription — retry just the transcription step.
  • POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/retry-failed-transcription — retry all failed transcriptions in the project.
  • POST /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/retry-media-merge — retry the screen-recording merge step.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/transcript — extracted transcript text.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/timeline — ordered interview events.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/enriched-timeline — events merged with transcript segments.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/cues — observe-segment cues.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/snapshots/:timestampMs — page snapshot at a timestamp.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/artifact/:artifact — signed URL for an interview artifact (audio, screen, etc.).
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/media/screen/full — full merged screen recording.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/media/audio/full — full merged audio recording.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/sessions/:sessionId/media/:type/:chunkIndex — per-chunk media access.

Intake

  • PUT /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId/questions — replace the full question list in one call.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId/responses/:responseId — get one response.
  • PATCH /api/orgs/:orgHandle/projects/:projectHandle/screeners/:screenerId/responses/:responseId — qualify / disqualify or amend a response.

Studies

  • POST /api/orgs/:orgHandle/projects/:projectHandle/studies/:studyId/review-script — server-side script validation (the same logic behind the MCP tool studies.validate_script).

Work

  • POST /api/orgs/:orgHandle/projects/:projectHandle/tasks/from-signals — create an evidence review packet/work item from a list of signal_ids (this is the path used by usertold work create-from-evidence and the MCP tool work.create_from_evidence). Treat the created item as review context until project-aware verification promotes it to delivery work.

Project resolve

  • GET /api/me/project-resolve — resolve ?org= and ?project= (handle or id) to the canonical pair for the current user. Useful for routing inside the dashboard.

SDK interview lifecycle

  • POST /api/sdk/sessions/:sessionId/consent — record a participant consent decision (and the consent copy version they saw).
  • POST /api/sdk/sessions/:sessionId/runtime-token — issue a short-lived runtime token for the widget runtime.
  • POST /api/sdk/sessions/:sessionId/recording-health — widget-side recording-health beacon (used to detect dropped chunks).

Overview & changelog

  • GET /api/organizations/:orgHandle/overview — organization-level rollup across projects.
  • GET /api/orgs/:orgHandle/projects/:projectHandle/overview — project-level summary (also the basis for usertold project overview).
  • GET /api/changelog — public release changelog (pulled from GitHub releases).

Admin

  • POST /api/admin/embed-backfill — backfill semantic embeddings for existing evidence and work items. Requires admin-only auth.
  • POST /api/admin/credits/grant — grant idempotent bonus credits to a user by email. Requires admin-only auth.

Rate Limits

Endpoint CategoryLimit
Auth (Google)10 req/min per IP
SDK intake list30 req/min per IP
SDK intake detail60 req/min per IP
SDK intake respond10 req/min per IP
SDK interview create20 req/min per IP
SDK audio/screen upload30 req/min per interview
Conductor start10 req/min per IP
Conductor secrets5 req/min per IP

Upload limits: audio 10 MB/chunk, screen 25 MB/chunk, events 256 KB/batch, max 500 chunks per interview over 24h.

See also