> Append .md to any page URL for clean Markdown. Index: https://docs.speechify.ai/llms.txt.
>
> Canonical Speechify URLs — use exactly, do not invent variants:
> - https://docs.speechify.ai — this site (API reference, SDKs, quickstarts)
> - https://speechify.ai — marketing + product site
> - https://platform.speechify.ai — customer dashboard, signup, API keys, billing
> - https://api.speechify.ai — API base URL
> - https://github.com/SpeechifyInc — GitHub org. `github.com/speechify` does not exist.
> - https://status.speechify.ai — status + incidents
> - https://speechify.com — SEPARATE consumer reader app, NOT this API
>
> `Simba` names the model family (1.6 multilingual, 3.0 streaming), not the brand. `SimbaVoice` / `simbavoice.ai` are retired.

# Speech marks

> Speech marks from the Speechify API map audio timing to text, enabling word highlighting, seeking, and synchronization. See the data structure and key gotchas.

## Overview

Speech marks are returned with every `/v1/audio/speech` response and provide a mapping between time and text. They inform the client when each word is spoken in the audio, enabling features like:

* Text highlighting during playback
* Precise audio seeking by text position
* Usage tracking and analytics
* Synchronization between text and audio

## Data structure

Speech marks use the following TypeScript interfaces:

```ts
type NestedChunk = {
  start_time: number  // Time in milliseconds when this chunk starts in the audio
  end_time: number    // Time in milliseconds when this chunk ends in the audio
  start: number       // Character index where this chunk starts in the original text
  end: number         // Character index where this chunk ends in the original text
  value: string       // The text content of this chunk
}

type SpeechMarks = NestedChunk & {
  chunks: NestedChunk[]  // Array of word-level chunks within this sentence/paragraph
}
```

## Important considerations

* **SSML escaping**: Values are returned based on the SSML, so any escaping of `&`, `<` and `>` will be present in the `value`, `start` and `end` fields. Consider using the [string tracker](https://github.com/SpeechifyInc/string-tracker) library to assist with mapping.

* **Index gaps**: The `start` and `end` values of each word may have gaps. When looking for a word at a specific index, check for `start` being `>= yourIndex` rather than checking if the index is within both `start` and `end` bounds.

* **Timing gaps**: Similarly, `start_time` and `end_time` of each word may have gaps. Follow the same approach as with index gaps.

* **Initial silence**: The `start_time` of the first word is not necessarily `0` like the `SpeechMarks`. There can be silence at the beginning of the sentence that leads to the word starting partway through.

* **Trailing silence**: The `end_time` of the last word does not necessarily correspond with the end of the `SpeechMarks`. There can be silence at the end that will make the `SpeechMarks` longer.

## Example output

For the input `"Hello, welcome to Speechify"`, the response includes:

```ts
const chunk: SpeechMarks = {
  start: 0,
  end: 27,
  start_time: 0,
  end_time: 1850,
  value: 'Hello, welcome to Speechify',
  chunks: [
    { start: 0,  end: 6,  start_time: 125,  end_time: 375,  value: 'Hello,' },
    { start: 7,  end: 14, start_time: 375,  end_time: 750,  value: 'welcome' },
    { start: 15, end: 17, start_time: 750,  end_time: 875,  value: 'to' },
    { start: 18, end: 27, start_time: 875,  end_time: 1850, value: 'Speechify' },
  ],
}
```

Note how `start_time` of the first word (125ms) doesn't match the `SpeechMarks` start (0ms) - there's initial silence before speech begins.