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 theSec-WebSocket-Protocol: access_token, <credential>subprotocol pair. - Scopes. A scope names an endpoint family across versions:
interhumanai.uploadcovers both upload endpoints and reading upload jobs, andinterhumanai.streamcovers both stream endpoints. An existing key or client token needs no new scope. A missing scope is still refused withih2003. See Authentication. - Client tokens. Mint them with
POST /v1/client_tokensas 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,messageover HTTP;data.codein a streamerrorenvelope). See Error handling. - Conversation Quality Index. Request it with the same
include[]/includevalues,conversation_quality_overallandconversation_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 withih5008. - 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 answers202 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):
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 withstatus: "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):
Upload checklist
- Send
model=inter-2. - Confirm your files carry both video and audio and fit the duration limit.
- Handle
202, pollstatus_url, and stop oncompletedorfailed. - Read signals from
result.windows[].signals[]and engagement fromresult.windows[].engagement_status. - Stop reading
modality. - Handle
ih4021for 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 towss://api.interhuman.ai/v2/stream/analyze.
Before (V1):
2. Select the model (optional)
A V2 session opens oninter-2 by default, so you do not need to name a model. To name one explicitly, use either of these:
- The
modelquery parameter on the handshake:wss://api.interhuman.ai/v2/stream/analyze?model=inter-2. A value the endpoint cannot take is refused with anih4005error envelope and close code1008. - The
modelfield of the session config frame. Unlikeinclude,modelis 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.
session.readylists the models you can select indata.supported_session_config_options.model.session.updatedreports the active model indata.model.
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):
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 examplevideo/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
modelin the query string or in a session config frame sent before the first video chunk. - Handle the
ih1003refusal (close code1013) when no backend serves the model. - Stop reading
data.modalityonsignal.detectedandsignal.updated. - Record chunks with an audio track.
Migrate with the SDKs
The TypeScript and Python SDKs cover both versions.- Stream: pass
{ apiVersion: "v2" }toclient.stream()in TypeScript, orapi_version="v2"in Python. The event types are the same on both versions; on V2,modalityis absent (TypeScript) orNone(Python) onsignal.detectedandsignal.updated. - Upload: replace
analyze()withsubmit(), which takes the model and returns the job envelope, and read the result withwaitForJob()(TypeScript) orwait_for_job()(Python). A failed job is returned rather than thrown, so check itsstatus.