# Transcribe a recording (OpenAI-compatible)

`POST https://api.paxalabs.com/v1/audio/transcriptions`

POST /v1/audio/transcriptions serves the OpenAI audio.transcriptions request shape. The recording rides as a multipart file part, and response_format returns JSON, plain text, SubRip, or WebVTT.

Point an OpenAI SDK at `https://api.paxalabs.com/v1` and call `audio.transcriptions.create`. Pricing, ceilings, and refunds match [POST /v1/stt](https://paxalabs.com/docs/api/stt), which is also where the transcript conventions, speaker turns, word timing, and the vocabulary live: this alias reads none of them. The [OpenAI compatibility guide](https://paxalabs.com/docs/openai-compatibility) covers the field mapping.

## Headers

- `authorization` (Bearer pxa_..., required): Authorization: Bearer pxa_... (recommended).
- `x-api-key` (pxa_..., optional): Alternative to the Authorization header. Ignored when Authorization is present.
- `idempotency-key` (string, optional, 1 to 200 characters, pattern ^[!-~]+$): Makes a retry safe. Two requests carrying the same key charge once and synthesize the same content. One request per key runs at a time. A concurrent duplicate answers 409 idempotency_in_flight. Reuse a key only to retry an identical request. A changed payload is rejected with 422. Accepts up to 200 printable ASCII characters.

See authentication at https://paxalabs.com/docs/authentication.

## Body

- `file` (file, required): The recording, as a file part. MP3, WAV (PCM), FLAC, Ogg (Opus or Vorbis), M4A, AAC (ADTS), or WebM; the format and the length are read from the bytes. The part's filename and content type are ignored. Same ceilings, pricing, and refusals as the audio field on POST /v1/stt: up to 60 minutes and 26,214,400 bytes.
- `model` (string, required, 1 to 100 characters): Transcription model id, for example paxa-stt-lite-v1-preview. OpenAI's own model names are not served and answer 400.
- `language` (string, optional, up to 16 characters, pattern ^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$): The same field OpenAI defines. A BCP 47 tag the recording is expected to be in, such as "th". A hint that filters nothing. Omitted, the model detects the language itself.
- `response_format` ("json" or "text" or "srt" or "vtt", optional, default "json"): What the response body carries. "json" (the default) answers application/json with the transcript in a text field. "text" answers text/plain with the transcript alone. "srt" and "vtt" answer the subtitle file, cut the same way POST /v1/stt cuts it, at 60 characters a line. OpenAI's verbose_json is not served and answers 400. Every format is billed the same, by the recording's length.

## Response

- `text` (string, required): The transcript, verbatim in the language spoken. Empty when the recording carried no speech.

## Errors

- `validation` (400): The request body or headers failed validation against the endpoint schema.
- `unknown_model` (400): The model field does not name a served model.
- `audio_invalid` (400): The audio field could not be read as an MP3, WAV, FLAC, Ogg, M4A, AAC, or WebM recording, or its length could not be read from the container. A damaged or truncated file answers this code. Nothing was charged.
- `audio_too_large` (413): The decoded recording exceeds the model's size ceiling. Nothing was charged.
- `audio_too_long` (400): The recording is longer than the model's per-request ceiling. Nothing was charged.
- `unauthorized` (401): The request carried no API key, or the key is invalid or disabled.
- `insufficient_credits` (402): The account does not have enough credits for this request. Nothing was charged.
- `key_limit` (403): This API key reached its spending cap. Nothing was charged.
- `idempotency_in_flight` (409): Another request with this Idempotency-Key is in flight right now.
- `idempotency_refunded` (409): The original request under this Idempotency-Key failed and was refunded.
- `idempotency_mismatch` (422): This Idempotency-Key was already used for a different request.
- `content_blocked` (422): The upstream safety system declined to process this content. The charge was refunded.
- `rate_limited` (429): Requests per minute for the plan are exhausted. One window covers the whole account, across every product and every key.
- `concurrency_limited` (429): The account holds the plan's full count of concurrent requests for this product. Nothing was charged. Each product is limited separately, and an open live connection holds one speech slot.
- `internal` (500): Request state was inconsistent on the server.
- `provider_error` (502): Model inference failed after the request was charged.
- `provider_unavailable` (503): The model behind this endpoint is not available right now. Nothing was charged.

## Example

curl:

```bash
# The recording rides as a file part; nothing is base64 encoded.
curl -X POST https://api.paxalabs.com/v1/audio/transcriptions \
  --max-time 300 \
  -H "Authorization: Bearer $PAXA_API_KEY" \
  -F file=@meeting.m4a \
  -F model=paxa-stt-lite-v1-preview \
  -F response_format=srt \
  -o meeting.srt
```

TypeScript:

```typescript
import { createReadStream } from "node:fs";
import { writeFile } from "node:fs/promises";
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.paxalabs.com/v1",
  apiKey: process.env.PAXA_API_KEY,
});

const subtitles = await client.audio.transcriptions.create({
  file: createReadStream("meeting.m4a"),
  model: "paxa-stt-lite-v1-preview",
  response_format: "srt",
});

await writeFile("meeting.srt", subtitles);
```

Python:

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.paxalabs.com/v1",
    api_key=os.environ["PAXA_API_KEY"],
)

with open("meeting.m4a", "rb") as file:
    subtitles = client.audio.transcriptions.create(
        file=file,
        model="paxa-stt-lite-v1-preview",
        response_format="srt",
    )

with open("meeting.srt", "w") as out:
    out.write(subtitles)
```
