> For the full page index, fetch https://echonova.ai/llms.txt

# Download a completed STT job as TXT, SRT or JSON

Returns the transcript of a completed API job of this key's workspace as a file: txt is the transcription text, srt is subtitles of at most 7 seconds and two 42-character lines per cue, each prefixed with its speaker label when speakers were identified, and json carries the text, speakers and timed segments. lang sets the language of the speaker labels. A job that has not completed answers 400; a job of another workspace answers 404. Needs Speech to Text access on the key.

## Endpoint

`GET https://api.echonova.ai/v1/speech-to-text/jobs/{jobId}/export`

## Authentication

Keys are created in the portal under Developers, sent as `Authorization: Bearer YOUR_API_KEY`. See [Get an API key](/docs/developers/get-an-api-key).

## Request

| Name   | In    | Type               | Required | Limits                      | Description                                                                                                                                          |
| ------ | ----- | ------------------ | -------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| jobId  | path  | string             | Yes      |                             | The jobId the API returned when the job was created.                                                                                                 |
| format | query | txt \| srt \| json | Yes      | one of txt, srt, json       | txt: the transcript text. srt: subtitles, one cue per few seconds, each tagged with its speaker when known. json: text, speakers and timed segments. |
| lang   | query | en \| ar           | No       | one of en, ar, default "en" | Language of the speaker labels: en gives "Speaker 1", ar gives "المتحدث 1".                                                                          |

## Responses

| Status | Description                                                                                            |
| ------ | ------------------------------------------------------------------------------------------------------ |
| 200    | The file, with Content-Disposition: attachment and its name; the body is not wrapped in { data, ... }. |
| 400    | Bad Request                                                                                            |
| 401    | Unauthorized                                                                                           |
| 403    | Forbidden                                                                                              |
| 404    | Not Found                                                                                              |
| 429    | Too Many Requests                                                                                      |
| 500    | Internal Server Error                                                                                  |
| 503    | Service Unavailable                                                                                    |
| 504    | Gateway Timeout                                                                                        |

## Response

A success answers 200 with the file itself, not the envelope `{ data, success, statusCode, errorMessage }`. The response carries `Content-Disposition: attachment` with the file name; an error is the usual error envelope.

`text/plain`:

```text
السلام عليكم، كيف حالك؟ بخير، الحمد لله.
```

`application/x-subrip`:

```text
1
00:00:00,380 --> 00:00:04,120
[Speaker 1] السلام عليكم، كيف حالك؟

2
00:00:04,300 --> 00:00:06,400
[Speaker 2] بخير، الحمد لله.
```

`application/json`:

```json
{
  "id": "66e3f2a1c9d4b8a1f0e12346",
  "fileName": "meeting.mp3",
  "durationSeconds": 312.4,
  "language": "ar",
  "text": "السلام عليكم، كيف حالك؟ بخير، الحمد لله.",
  "speakers": [
    {
      "id": "spk0",
      "label": "Speaker 1",
      "talkTime": 4.12
    },
    {
      "id": "spk1",
      "label": "Speaker 2",
      "talkTime": 2.1
    }
  ],
  "segments": [
    {
      "start": 0.38,
      "end": 4.12,
      "speaker": "spk0",
      "speakerLabel": "Speaker 1",
      "text": "السلام عليكم، كيف حالك؟"
    },
    {
      "start": 4.3,
      "end": 6.4,
      "speaker": "spk1",
      "speakerLabel": "Speaker 2",
      "text": "بخير، الحمد لله."
    }
  ]
}
```

## Errors

| Status | errorMessage                                                 | When                                                                                                                                                                                                                                                                                       | Fix                                                                                                       |
| ------ | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| 400    | Invalid identifier                                           | jobId is not a 24-character hexadecimal id.                                                                                                                                                                                                                                                | Use the id exactly as the create call returned it.                                                        |
| 400    | format must be one of the following values: txt, srt, json   | The format query parameter is missing or is not txt, srt or json.                                                                                                                                                                                                                          | Send format=txt, format=srt or format=json.                                                               |
| 400    | lang must be one of the following values: en, ar             | The lang query parameter is something other than en or ar.                                                                                                                                                                                                                                 | Send lang=en or lang=ar, or leave it out for en.                                                          |
| 400    | Job is not completed                                         | The job is pending, processing or failed; only a completed job has a transcript to download.                                                                                                                                                                                               | Wait for the job.completed webhook or poll GET /v1/speech-to-text/jobs/{jobId} until status is completed. |
| 400    | property <name> should not exist                             | The body or query carries a field the endpoint does not define.                                                                                                                                                                                                                            | Remove the field.                                                                                         |
| 401    | Unauthorized                                                 | The Authorization header is missing or is not Bearer ek\_..., no key matches the token, or the key is deleted, disabled or its account is closed.                                                                                                                                          | Send Authorization: Bearer ek\_... with an enabled key from this environment.                             |
| 403    | Subscription not found                                       | The workspace that owns the key has no subscription.                                                                                                                                                                                                                                       | Check the workspace's plan in the portal.                                                                 |
| 403    | Subscription expired or inactive                             | The subscription is in a state other than active or trial.                                                                                                                                                                                                                                 | Renew the subscription.                                                                                   |
| 403    | This API key does not have access to Speech-to-Text services | The key is restricted and Speech to Text is not among its services.                                                                                                                                                                                                                        | Edit the key and grant Speech to Text, or use another key.                                                |
| 404    | STT Job not found                                            | The job id is unknown, or the job belongs to another workspace or was made in the portal.                                                                                                                                                                                                  | Use a jobId from this workspace's API jobs.                                                               |
| 429    | ThrottlerException: Too Many Requests                        | The key made more than 100 requests to one endpoint in 60 seconds, or one IP address made more than 100 requests to one endpoint in 60 seconds (the IP limit is counted before the key is checked, so it can answer with no key at all); a Retry-After header carries the seconds to wait. | Wait Retry-After seconds, then retry.                                                                     |
| 500    | Something went wrong                                         | An error the API did not classify.                                                                                                                                                                                                                                                         | Check the request, then retry after a short wait; contact support if it persists.                         |
| 503    | Database unavailable                                         | A transient outage inside the API.                                                                                                                                                                                                                                                         | Retry after a short wait.                                                                                 |
| 504    | Database timed out                                           | A transient timeout inside the API.                                                                                                                                                                                                                                                        | Retry after a short wait.                                                                                 |

## Code samples

:::tabs

```bash title="cURL"
curl "https://api.echonova.ai/v1/speech-to-text/jobs/{jobId}/export?format=srt&lang=en" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -o download.srt
```

```python
import requests

response = requests.get(
    "https://api.echonova.ai/v1/speech-to-text/jobs/{jobId}/export?format=srt&lang=en",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
response.raise_for_status()
with open("download.srt", "wb") as out:
    out.write(response.content)
```

```javascript
import { writeFile } from 'node:fs/promises';

const response = await fetch('https://api.echonova.ai/v1/speech-to-text/jobs/{jobId}/export?format=srt&lang=en', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_API_KEY',
  },
});
if (!response.ok) throw new Error((await response.json()).errorMessage);
await writeFile('download.srt', Buffer.from(await response.arrayBuffer()));
```

:::
