Skip to main content
The V2 endpoints analyze with Inter-2, which is faster and more accurate than Inter-1. This guide covers the client changes for each endpoint pair: The V2 endpoints are served beside the V1 endpoints, so you can migrate one endpoint at a time.

What stays the same

  • Base URL and credentials. Send the same API key, or a client token minted from it, as Authorization: Bearer <credential>. Browser WebSocket clients keep using the Sec-WebSocket-Protocol: access_token, <credential> subprotocol pair.
  • Scopes. A scope names an endpoint family across versions: interhumanai.upload covers both upload endpoints and reading upload jobs, and interhumanai.stream covers both stream endpoints. An existing key or client token needs no new scope. A missing scope is still refused with ih2003. See Authentication.
  • Client tokens. Mint them with POST /v1/client_tokens as before. A token’s video budget (max_video_seconds) is shared across upload and stream on either version.
  • Errors. Every error uses the same shape (error_id, correlation_id, link, message over HTTP; data.code in a stream error envelope). See Error handling.
  • Conversation Quality Index. Request it with the same include[] / include values, conversation_quality_overall and conversation_quality_timeline.

Migrate upload

On V1, one request uploads the file and returns the analysis. On V2, the upload creates an analysis job: the request returns a job envelope, and you read the result from the job once it finishes.

1. Name the model

model is a required form field on POST /v2/upload/analyze. Send model=inter-2. An unknown value is refused with 400 (ih4005).

2. Check the file

V2 accepts the same containers (mp4, mov, avi, mkv, webm, mpeg-ts), the same 32 MB limit, and the same 3-second minimum. Two requirements are new:
  • The file must carry both a video and an audio track. A file without video is refused with ih5001, and a file without audio with ih5008.
  • The media must be no longer than 30 minutes. A longer file is refused with ih4004.

3. Submit the job and read the result

The submit answers 202 with a job envelope whose status is queued. Read GET /v2/upload/jobs/{job_id} (the envelope’s status_url) until status is completed or failed. The status moves through queued and running before it reaches one of those two terminal values. To skip polling for short files, send wait_seconds. The API holds the request open for up to that many seconds and answers 200 with the job when it reaches completed or failed in time, or 202 with the pending job when it does not. A value above 120 seconds is refused with ih4005. Keep the polling path either way. Before (V1):
After (V2):
status_url is a path relative to the API base URL, not an absolute URL.

4. Handle job failures and expiry

Validation still happens at submit, so a missing file, an unsupported container, or a file that is too short or too long fails the submit request with the usual HTTP error. A failure during the analysis itself does not: the job ends with status: "failed", and its error field carries the standard error body. Check status before you read result. A job that fails with ih1004 was interrupted before it finished; submit the file again. A job stays readable until its expires_at (1 hour after submission). After that, and for an id that does not belong to your account, the read answers 404 (ih4021). Store the result on your side if you need it longer. When the API cannot take a job right now, the submit answers 503 (ih1002 or ih1003). Retry after a short delay.

5. Read the new result shape

The V1 response lists signals and engagement states over the whole file. The V2 result divides the file into fixed-length windows and reports each window separately. A V2 signal’s start and end are the span of the window it was detected in. To list every signal in the file, flatten windows[].signals[]. Before (V1):
After (V2), a completed job:

Upload checklist

  • Send model=inter-2.
  • Confirm your files carry both video and audio and fit the duration limit.
  • Handle 202, poll status_url, and stop on completed or failed.
  • Read signals from result.windows[].signals[] and engagement from result.windows[].engagement_status.
  • Stop reading modality.
  • Handle ih4021 for expired jobs.

Migrate stream

WS /v2/stream/analyze speaks the same protocol as WS /v1/stream/analyze: the same handshake and authentication, the same session config frame, binary video chunks in, and the same envelope types out, including the graceful session.close handshake. For most clients, the migration is a path change plus two payload details.

1. Change the path

Connect to wss://api.interhuman.ai/v2/stream/analyze. Before (V1):
After (V2):

2. Select the model (optional)

A V2 session opens on inter-2 by default, so you do not need to name a model. To name one explicitly, use either of these:
  • The model query parameter on the handshake: wss://api.interhuman.ai/v2/stream/analyze?model=inter-2. A value the endpoint cannot take is refused with an ih4005 error envelope and close code 1008.
  • The model field of the session config frame. Unlike include, model is session state: a config frame that omits it keeps the current model, and a frame that changes it is accepted only before the first video chunk.
V2 reports the model on two envelopes that V1 leaves empty:
  • session.ready lists the models you can select in data.supported_session_config_options.model.
  • session.updated reports the active model in data.model.
On V1, both fields are null, and a session config frame that names a model is rejected. If no backend serves the selected model, the session is refused after the handshake with an ih1003 error envelope and close code 1013. Nothing is analyzed or billed; retry later.

3. Update signal handling

signal.detected and signal.updated on V2 carry signal_type, start, probability, and rationale, with no modality field. Remove any code that reads or requires data.modality. On V2, signal.updated is emitted when an active signal’s probability or rationale changes, so an update can repeat the previous probability. V2 carries no modality, so a change in modality never triggers an update. Before (V1):
After (V2):
Every other envelope keeps its V1 payload: session.ready and session.updated (apart from model), signal.ended, engagement.updated, conversation_quality.updated, coverage.degraded, coverage.dropped, session.closing, session.ended, and error.

4. Send audio with the video

Inter-2 requires sound as well as a picture. Record your chunks with an audio track, for example video/webm;codecs=vp9,opus from MediaRecorder with a stream from getUserMedia({ video: true, audio: true }).

Stream checklist

  • Change the path to /v2/stream/analyze.
  • Optionally name model in the query string or in a session config frame sent before the first video chunk.
  • Handle the ih1003 refusal (close code 1013) when no backend serves the model.
  • Stop reading data.modality on signal.detected and signal.updated.
  • Record chunks with an audio track.

Migrate with the SDKs

The TypeScript and Python SDKs cover both versions.
  • Stream: pass { apiVersion: "v2" } to client.stream() in TypeScript, or api_version="v2" in Python. The event types are the same on both versions; on V2, modality is absent (TypeScript) or None (Python) on signal.detected and signal.updated.
  • Upload: replace analyze() with submit(), which takes the model and returns the job envelope, and read the result with waitForJob() (TypeScript) or wait_for_job() (Python). A failed job is returned rather than thrown, so check its status.
See the TypeScript SDK and Python SDK references for the full signatures.