Skip to main content

Trigger Speaker Name Inference Suggestions Route

POST 

/v2/audios/{audio_id}/speaker-name-inference/suggestions

Trigger speaker-name inference in suggestions mode: same model pass and evidence grounding as POST .../speaker-name-inference, same result rows, writes nothing.

audios.speakers[].name is left byte-identical. No manual_name_inference_runs audit append and no Deal-Person linking fire. The client reviews results and commits accepted names through existing rename endpoints that do not charge:

  • PUT /v1/audios/{audio_id}/speakers/names — names only, including speakers with no matched face. Unlike the committing inference POST, a commit here may overwrite an OCR-derived face name on a completed parent video. Unknown speaker_ids are skipped with a 200; there is no audio.status == "completed" check and no parent-video check. A suggestion committed after a speaker merge/delete can silently no-op. A name committed while the parent video is still processing can be overwritten with Face {id} when speaker-face matching writes back. This is the primary commit path for both audio-only media and video-backed audio.
  • PUT /v2/videos/{video_id}/speaker-face-match (name field; requires face_id) — updates both face and speaker. Only available when this audio has a parent video. Speakers with no matched face are out of scope. Unknown speaker_id / face_id raise InvalidSpeaker / InvalidFace; the video must be completed. A stale id is a 4xx, not a silent skip.

Neither PUT re-runs this endpoint's validation (no synthetic-track refusal, no duplicate-name guard). They also do not restore the Deal-Person linking or manual_name_inference_runs stamp that the committing POST performs (follow-up: #1375). Identify-people Save via this route then a PUT is a smaller feature than the committing POST.

Duplicate-name grounding is per call against persisted speaker names. Because this path writes nothing, two sequential per-speaker suggestion calls can both accept the same name (e.g. "Alice"), and neither PUT dedupes.

Every successful call is billed. The amount is not quoted on the request; it is recorded after the run. A 502 (model failure or unparseable response) is not billed. The call is not idempotent: a double click is two model calls and two charges. The client must disable the control while in flight and must not blindly retry a gateway timeout — the request may still complete and charge after the client has given up.

Body and auth match the sibling POST. Audio must be completed; unlike the committing POST, an in-flight parent is not a 409. Synchronous: holds the connection for the model call. An all-rejected result is a successful billed run.

Request Body (required)

  • target_speaker_ids: required, non-empty list of speaker ids to (re-)name.
  • infer_roles: optional, default false. When true, the same model pass also proposes agent or customer per targeted speaker, grounded in a quote from that speaker's own words. Independent of the name verdict. Roles are never written; commit them via PUT /v1/audios/{audio_id}/speakers/roles. A speaker whose stored role is already agent or customer is not offered a new role (role_already_set); clear the role and re-run to get a fresh proposal. Omitted and false are the same request. This is the path for a role proposal without a possible rename.

Prerequisites

  • User must be the audio owner or hold MEDIA_WRITE
  • Audio must be in 'completed' status. An in-flight parent video does not 409 this path: this call writes nothing. Committing a suggestion via PUT while the parent is still processing is a documented race (see the commit-path bullet above)
  • The audio must be eligible for transcript-based name inference (non-meeting upload with no provider-supplied transcript/diarization and no speech_segments pointer) and its transcript must already be available. A supplied or replaced transcript is a permanent 400, not a retryable state
  • Caller must have a positive credit balance. This call is billed on success; the amount is not quoted here. A 402 is returned before the model runs when admission is refused

Response

Returns at least one result row per requested target_speaker_id, each either an accepted proposal (name, quote, pattern) or a rejection (reason) — including a row for any targeted speaker the model could not resolve. Duplicate model rows for the same id, if any, are not collapsed. When infer_roles is true, each row also carries an independent role verdict (role_accepted, and on accept role plus role_quote). Roles are not mutually exclusive across speakers. video_id is set when this audio has a parent video; it is null for audio-only media.

Error Responses

  • 401 Unauthorized: User is not authenticated or not authorized to access this audio
  • 404 Not Found: Audio not found
  • 409 Conflict: Audio processing not completed
  • 400 Bad Request: Transcript not ready, target_speaker_ids is empty, contains a speaker ID not present in the audio or naming a synthetic track, the audio (or its parent video) is not eligible for this feature, or video_id points at a missing video
  • 402 Payment Required: Admission refused. Detail is the admission refusal_message. The wording differs for a zero vs. negative balance vs. a window refusal (buying credits does not fix the latter)
  • 422 Unprocessable Entity: target_speaker_ids is missing/null, or contains a non-integer entry; or infer_roles is null or not a boolean
  • 502 Bad Gateway: The model call failed or returned an unparseable response. No charge is applied

Request

Responses

Successful Response