# Transcriptions API

Converts speech in an audio file to text. The endpoint is compatible with the OpenAI audio transcription API.

`POST https://api.ifm.ai/v1/audio/transcriptions`

## Request

The request body is `multipart/form-data`: the audio file plus the fields below. Leave `language` out and the model detects the spoken language automatically.

```
curl https://api.ifm.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $IFM_API_KEY" \
  -F file=@meeting.wav \
  -F model="IFM/Jais-ASR"
```

### Body parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `file` | file | required | The audio file to transcribe. See Supported formats. |
| `model` | string | required | Transcription model ID, e.g. `IFM/Jais-ASR`. |
| `language` | string | — | Language or dialect hint. Case-insensitive. Omitting it is recommended; see Language. |
| `code_switch` | boolean | `true` | When `true`, foreign words spoken within Arabic speech (such as English terms) are written in Latin script. When `false`, they are transliterated into Arabic script. |
| `diacritics` | boolean | `false` | When `true`, Arabic output includes diacritics (tashkeel). |
| `max_completion_tokens` | integer | `1024` (max `2048`) | Maximum number of tokens the model can generate for each chunk of up to 30 seconds of audio. The default is sufficient in almost all cases; see `truncated` under Response. |

### Passing extra parameters with the OpenAI SDK

`code_switch`, `diacritics`, and `max_completion_tokens` are not part of the OpenAI SDK's method signature, so pass them through `extra_body`. With curl, send them as ordinary form fields.

```
curl https://api.ifm.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $IFM_API_KEY" \
  -F file=@meeting.wav \
  -F model="IFM/Jais-ASR" \
  -F language=ar \
  -F code_switch=false \
  -F diacritics=true
```

## Language

**Leave `language` unset.** The model identifies the spoken language or dialect on its own and returns it in the response's `language` field. This is the recommended path for every workload, including dialect audio.

Set `language` only when you are certain of the input. Setting it turns off detection: the model transcribes the audio as the language you named, and the response's `language` field echoes your hint instead of a detected value. The right hint, such as `language=eg` for Egyptian Arabic, can improve accuracy.

The exception is `language=ar`. It tells the model the audio is Arabic but keeps detection between Modern Standard Arabic and the dialects, so the response still returns the detected variety, such as `[msa]` or `[EG]`. Use it when you know the audio is Arabic but not which dialect.

When `language` is unset, detection returns a single label per segment: the majority language in that stretch of audio. Speech that mixes languages is not labeled language by language. To control how foreign words within Arabic speech are written, use `code_switch`.

### Language codes

Codes are case-insensitive, so `eg`, `EG`, and `Eg` are equivalent.

| Language | Code |
| --- | --- |
| Arabic, including all supported dialects | ar |
| Modern Standard Arabic | msa |
| English | en |
| French | fr |
| Spanish | es |
| Italian | it |

Use `ar` when the audio is Arabic but you don't know the dialect (the response still reports the detected dialect or MSA), `msa` for Modern Standard Arabic, or one of the dialect codes below:

| Code | Dialect |
| --- | --- |
| `DZ` | Algerian |
| `BH` | Bahraini |
| `EG` | Egyptian |
| `IQ` | Iraqi |
| `JO` | Jordanian |
| `KW` | Kuwaiti |
| `LB` | Lebanese |
| `LY` | Libyan |
| `MR` | Mauritanian |
| `MA` | Moroccan |
| `OM` | Omani |
| `PS` | Palestinian |
| `QA` | Qatari |
| `SA` | Saudi |
| `SD` | Sudanese |
| `SY` | Syrian |
| `TN` | Tunisian |
| `AE` | Emirati |
| `YE` | Yemeni |

## Response

`200 · application/json`

```
{
  "text": "نبدأ الاجتماع بمراجعة أرقام الربع الثالث.",
  "language": "[msa]",
  "no_speech": false,
  "truncated": false
}
```

| Field | Type | Description |
| --- | --- | --- |
| `text` | string | The transcript. Empty when no speech is detected. |
| `language` | string \| null | Detected language tag. Always wrapped in brackets (e.g. `[msa]`, `[EG]`) to mark it as a tag emitted by the model; strip the brackets if you want to reuse it as a `language` hint. `null` when no speech is detected. |
| `no_speech` | boolean | `true` if no speech was detected in the audio. |
| `truncated` | boolean | `true` if the model's token budget ran out before it finished transcribing a chunk, so part of the speech is missing from `text`. This is rare at the default budget; if it happens, raise `max_completion_tokens`. |

With the OpenAI SDK, `language`, `no_speech`, `truncated`, `duration_seconds`, and `segments` are not typed attributes. Read them from `result.model_extra`, e.g. `result.model_extra["language"]`. The SDK's own `languages` attribute is not populated and will show as `None`.

### Long audio (over 30 seconds)

Audio longer than 30 seconds is split into chunks automatically. Split points are placed at low-energy moments, such as pauses, using vLLM's default chunking, so each chunk is at most about 30 seconds.

The response then includes two additional fields, and the top-level `text` is the transcript of all chunks concatenated:

| Field | Type | Description |
| --- | --- | --- |
| `duration_seconds` | number | Total duration of the audio, in seconds. |
| `segments` | array | One entry per chunk, in order. Each has `start` and `end` (in seconds) plus `text`, `language`, `no_speech`, and `truncated`, with the same meaning as above but for that chunk only. |

Segments with no speech stay in the array, with an empty `text`, `no_speech: true`, and `language: null`. The segments therefore always cover the full duration of the audio without gaps.

## Supported formats

| Container | Extensions | Notes |
| --- | --- | --- |
| FLAC | flac | Lossless |
| MP3 | mp3 | Any bitrate |
| OGG | ogg, oga | Vorbis or Opus |
| WAV | wav | PCM, 16-bit or 24-bit |
| WEBM | webm | Opus audio track |

Stereo audio is downmixed to mono before transcription. The maximum file size is **32 MB**, and the maximum audio length is **15 minutes**.

_Last updated: October 14, 2026_
