---
title: "Change, confirm or move a labelled passage"
method: PATCH
path: "/media/{mediaId}/labels/{mediaLabelId}"
tags: ["Labels"]
---

# Change, confirm or move a labelled passage

`PATCH /media/{mediaId}/labels/{mediaLabelId}`

## Request

- Base URL: `https://api.speakai.co/v1`
- URL: `https://api.speakai.co/v1/media/{mediaId}/labels/{mediaLabelId}`
- Auth: API key in header `x-speakai-key` and API key in header `x-access-token`

Requires the **Labels: Assign** permission. Send exactly one of `labelIds` or `action`; both or neither returns 400.

- `labelIds` replaces the passage's labels, with the same rules as when you label a passage.
- `action: "keep"` confirms the passage where it is now: `status` becomes `active` and `lastResolved` is cleared. Use it on a `shifted` passage, or to accept the suggestion on a `needs_review` one. It returns 409 if the passage is still on an older revision, which happens for a moment after a save.
- `action: "replace"` moves the passage to new words. It needs `range` and `expectedTranscriptRevision`, which are not allowed with any other choice. `expectedTranscriptRevision` is the `transcriptRevision` you read the transcript at, from `GET /media/transcript/{mediaId}`, `GET /media/insight/{mediaId}`, or the list endpoints on this page. The server builds the anchor from its own copy of the transcript. If the transcript has been saved since, the request returns 409 "This transcript changed since you opened it. Reload to keep editing." and nothing is written: read the transcript again and recompute the word range.

#### Errors

- `400` when the body breaks the rules above, the range runs past the transcript, or a label cannot be applied.
- `403` without the permission.
- `404` when the media or the labelled passage does not exist.
- `409` when the revision is stale.

## Path parameters

- `mediaId` string, required
- `mediaLabelId` string, required

## Request body

- object
  - `labelIds` string[]: Labels to put on the passage. 1 to 20 ids, no repeats. Each must be an active label (not a group) in your company, or the request returns 400 "Choose active labels from this workspace (groups cannot be applied)."
  - `action` 'keep' | 'replace': `keep` to confirm the current position, `replace` to move the passage.
  - `range` object: Required with `action: "replace"`, not allowed otherwise. Inclusive range of word positions. Word positions count every word of the transcript in order, starting at 0. Within each sentence, words come from `entities` in order (an entity that holds several words, such as "New York", counts as several), or from the sentence `text` split on whitespace when the sentence has no entities. A token that is only punctuation is not counted.
    - `start` integer, required: Position of the first word. Integer, 0 or more.
    - `end` integer, required: Position of the last word, inclusive. Integer, at least `start`. A range that runs past the last word returns 400 "The selected words are outside this transcript."
  - `expectedTranscriptRevision` integer: Required with `action: "replace"`, not allowed otherwise. The `transcriptRevision` you read the transcript at. Integer, 0 or more. A stale value returns 409.

## Response `200`

Success

- object
  - `status` 'success': `success` on every 2xx response.
  - `data` object: Labels on one passage of a transcript.
    - `mediaLabelId` string: Id of the labelled passage.
    - `mediaId` string: Id of the media.
    - `labelIds` string[]: Labels on the passage.
    - `anchor` object: Where the passage sits in the transcript. Built by the server from the word range you send.
      - `startWord` integer: Position of the first word.
      - `endWord` integer: Position of the last word, inclusive.
      - `exact` string: The quoted words, joined by single spaces.
      - `prefix` string: Up to 32 characters of transcript text before the quote.
      - `suffix` string: Up to 32 characters of transcript text after the quote.
      - `startInSec` number: Start time of the first word, in seconds.
      - `endInSec` number: End time of the last word, in seconds.
      - `speakerIds` string[]: Speakers of the quoted words.
      - `transcriptRevision` integer: The transcript revision these positions refer to.
    - `status` 'active' | 'shifted' | 'needs_review': `active`: the same words, possibly at new positions after an edit. `shifted`: most of the words survived an edit near the same time, but the text changed. `needs_review`: the words changed too much to follow; `anchor` then holds a suggested passage on the new transcript and `lastResolved` the last position a person confirmed.
    - `lastResolved` object: Present only while `status` is `needs_review`: the last position a person confirmed.
      - `startWord` integer: Position of the first word.
      - `endWord` integer: Position of the last word, inclusive.
      - `exact` string: The quoted words, joined by single spaces.
      - `prefix` string: Up to 32 characters of transcript text before the quote.
      - `suffix` string: Up to 32 characters of transcript text after the quote.
      - `startInSec` number: Start time of the first word, in seconds.
      - `endInSec` number: End time of the last word, in seconds.
      - `speakerIds` string[]: Speakers of the quoted words.
      - `transcriptRevision` integer: The transcript revision these positions refer to.
    - `userId` string: Id of the person who first labelled the passage.
    - `createdAt` string, date-time: When it was created.
    - `updatedAt` string, date-time: When it last changed.

## Other responses

- `400`: The body broke a rule or failed validation
- `403`: You lack the Labels: Assign permission
- `404`: The media or the labelled passage does not exist
- `409`: The transcript changed since you read it

---

[API](https://skmtc.dev/speakai/apis/speak-ai-api.md) · [All operations](https://skmtc.dev/speakai/apis/speak-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/speakai/apis/speak-ai-api/revisions/52d777e6d46e?raw)
