> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://api.llynx.io/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://api.llynx.io/docs/_mcp/server.

# Transcribe a recording (STT)

POST https://api.llynx.io/v2/audio/transcriptions
Content-Type: multipart/form-data

Turns a short recording into text.

Send an audio file of up to 60 seconds together with the language spoken in it, and receive the transcript as JSON with the billable duration. Use it for voice notes, call snippets, voice commands and dictation.

Each recording is transcribed in the one language you name, chosen from the [Languages](/docs/capabilities) page; automatic detection is available only when the catalog lists it. Requests are charged by the duration of the audio, rounded up to the next whole second, at 20 seconds per credit.

Reference: https://api.llynx.io/docs/api-reference/transcribe

## Authentication

- `Authorization` header (bearer token, required) — Your Llynx API key, sent as `Authorization: Bearer <key>`.

## Request

### Body (multipart/form-data)

This endpoint expects a multipart form containing a file.

- `file` (file, required) — The recording: WAV, MP3, M4A, FLAC, Ogg or WebM, mono or stereo, 8–48 kHz, up to 60 seconds and 32 MiB.
- `language` (string, required) — Language spoken in the recording, as a tag from the Languages page, for example `hi` or `en`. `auto` is accepted only when the catalog lists it.

## Response

### 200

Transcript and billable duration

- `id` (string, required) — Identifier of this request, also sent as the X-Request-ID header; quote it when you contact us about a charge.
- `text` (string, required) — The transcript.
- `language` (string, required) — Language used for the transcription.
- `language_mode` (enum, required) — `explicit` when you named the language, `auto` when it was detected.
  - Allowed values: `explicit`, `auto`
- `duration_ms` (integer, required) — Decoded audio duration in milliseconds.
- `capabilities_revision` (string, required) — Version of the language catalog in force for this request (v1, v2, ...), as shown on the Languages page.
- `usage` (TranscriptionUsage, required)

## Errors

### 400 Bad Request Error

A field is missing or malformed

- `error` (ErrorError, required)

### 401 Unauthorized Error

Missing or invalid API key

- `error` (ErrorError, required)

### 402 Payment Required Error

Not enough credit for this service; buy a pack

- `error` (ErrorError, required)

### 403 Forbidden Error

This key or account is not allowed to make the request, or the account is on a billing hold

- `error` (ErrorError, required)

### 413 Content Too Large Error

Request body too large

- `error` (ErrorError, required)

### 415 Unsupported Media Type Error

Unsupported audio format

- `error` (ErrorError, required)

### 422 Unprocessable Entity Error

The input could not be processed, for example an unsupported language

- `error` (ErrorError, required)

### 429 Too Many Requests Error

Capacity limit reached; retry later when `retryable` is true

- `error` (ErrorError, required)

### 503 Service Unavailable Error

Temporarily unavailable; a request that fails after admission is refunded

- `error` (ErrorError, required)

## Types

### TranscriptionUsage

- `credit_unit` (enum, required) — Always `stt_credit`.
  - Allowed values: `stt_credit`
- `credits_reserved` (double, required) — Credits reserved for this request; settlement follows the response.
- `billable_seconds` (integer, required) — Audio seconds charged, rounded up to the next second.

### ErrorError

- `code` (string, required) — Stable machine-readable code.
- `message` (string, required) — Readable explanation, safe to log.
- `request_id` (string, required) — Quote this when you contact us about the request.
- `retryable` (boolean, required) — True only when an immediate retry is safe.

## Examples

**Request**

```json
{
  "file": "<file: voice-note.m4a>",
  "language": "hi"
}
```

**SDK Code**

```python Python
import os
import requests

with open("voice-note.m4a", "rb") as audio:
    response = requests.post(
        "https://api.llynx.io/v2/audio/transcriptions",
        headers={"Authorization": f"Bearer {os.environ['LLYNX_API_KEY']}"},
        files={"file": ("voice-note.m4a", audio, "audio/mp4")},
        data={"language": "hi"},
    )
response.raise_for_status()
result = response.json()
print(result["text"])
```

```javascript JavaScript
import { readFile } from "node:fs/promises";

const form = new FormData();
form.append("file", new Blob([await readFile("voice-note.m4a")], { type: "audio/mp4" }), "voice-note.m4a");
form.append("language", "hi");

const response = await fetch("https://api.llynx.io/v2/audio/transcriptions", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LLYNX_API_KEY}` },
  body: form,
});
if (!response.ok) throw new Error(await response.text());
const result = await response.json();
console.log(result.text);
```

```go Go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	audio, err := os.ReadFile("voice-note.m4a")
	if err != nil {
		log.Fatal(err)
	}

	var form bytes.Buffer
	w := multipart.NewWriter(&form)
	part, _ := w.CreateFormFile("file", "voice-note.m4a")
	part.Write(audio)
	w.WriteField("language", "hi")
	w.Close()

	req, _ := http.NewRequest("POST", "https://api.llynx.io/v2/audio/transcriptions", &form)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("LLYNX_API_KEY"))
	req.Header.Set("Content-Type", w.FormDataContentType())

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		log.Fatalf("%s: %s", resp.Status, body)
	}
	var result struct {
		Text string `json:"text"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		log.Fatal(err)
	}
	fmt.Println(result.Text)
}
```

```java Java
import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;

public class Transcribe {
    public static void main(String[] args) throws Exception {
        String boundary = UUID.randomUUID().toString();
        ByteArrayOutputStream form = new ByteArrayOutputStream();
        form.write(("--" + boundary + "\r\n"
            + "Content-Disposition: form-data; name=\"file\"; filename=\"voice-note.m4a\"\r\n"
            + "Content-Type: audio/mp4\r\n\r\n").getBytes(StandardCharsets.UTF_8));
        form.write(Files.readAllBytes(Path.of("voice-note.m4a")));
        form.write(("\r\n--" + boundary + "\r\n"
            + "Content-Disposition: form-data; name=\"language\"\r\n\r\nhi\r\n"
            + "--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8));

        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.llynx.io/v2/audio/transcriptions"))
            .header("Authorization", "Bearer " + System.getenv("LLYNX_API_KEY"))
            .header("Content-Type", "multipart/form-data; boundary=" + boundary)
            .POST(HttpRequest.BodyPublishers.ofByteArray(form.toByteArray()))
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() != 200) {
            throw new RuntimeException(response.statusCode() + " " + response.body());
        }
        // The body is JSON with the transcript in "text"; parse it with your JSON library.
        System.out.println(response.body());
    }
}
```

```swift Swift
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let key = ProcessInfo.processInfo.environment["LLYNX_API_KEY"] ?? ""
let boundary = UUID().uuidString
var form = Data()
form.append(Data("--\(boundary)\r\nContent-Disposition: form-data; name=\"file\"; filename=\"voice-note.m4a\"\r\nContent-Type: audio/mp4\r\n\r\n".utf8))
form.append(try Data(contentsOf: URL(fileURLWithPath: "voice-note.m4a")))
form.append(Data("\r\n--\(boundary)\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\nhi\r\n--\(boundary)--\r\n".utf8))

var request = URLRequest(url: URL(string: "https://api.llynx.io/v2/audio/transcriptions")!)
request.httpMethod = "POST"
request.setValue("Bearer \(key)", forHTTPHeaderField: "Authorization")
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.httpBody = form

let (data, response) = try await URLSession.shared.data(for: request)
let http = response as! HTTPURLResponse
guard http.statusCode == 200 else {
    fatalError("\(http.statusCode): \(String(decoding: data, as: UTF8.self))")
}
let result = try JSONSerialization.jsonObject(with: data) as! [String: Any]
print(result["text"] as! String)
```