# Sell transcription

This page is for a provider that turns audio into text. It tells you why you need an agent, what your upstream must answer, and how to register the deployment.

## Use an agent

A transcription job needs an agent. The [OpenAI-compatible path](https://inference.ai.exchange/docs/provider-openai.md) does not carry it, and the exchange sends the job to the next offer. The agent reads the audio from the job, posts it to your upstream, and reports the seconds that it transcribed.

## Give the agent this route

The agent calls `POST {base}/audio/transcriptions` with `Authorization: Bearer <key>`. Set `{base}` in `LIQUID_UPSTREAM_BASE_URL`.

The body is `multipart/form-data`:

| Field                       | Value                                                                |
| --------------------------- | -------------------------------------------------------------------- |
| `file`                      | The audio, named `audio.<format>`. A job has exactly one audio part. |
| `model`                     | The upstream model of the deployment.                                |
| `response_format`           | Always `verbose_json`.                                               |
| `language`, `prompt`        | Present only when the buyer set them.                                |
| `temperature`               | Present only when the buyer set it.                                  |
| `timestamp_granularities[]` | One field for each granularity that the buyer asked for.             |

Your upstream must support `verbose_json`. The job is metered on its duration, and only that form holds the duration.

Answer with JSON:

```json
{
  "text": "The auction is open.",
  "language": "en",
  "duration": 3.4,
  "segments": [{ "id": 0, "start": 0.0, "end": 3.4, "text": "The auction is open." }],
  "words": [{ "word": "The", "start": 0.0, "end": 0.2 }]
}
```

- `text` is required.
- `duration`, in seconds, is required. The agent also accepts `usage.seconds`. An answer with neither fails the job.
- `language`, `segments` and `words` are optional.

The agent rounds the duration up to whole seconds and meters that number.

## Declare the controls

- `transcription.diarize`: the buyer asked for a `speaker` on each segment. The dispatch has `diarize: true`.
- `transcription.keyterms`: the buyer gave words that the transcript must spell as given. The dispatch has a list of `keyterms`.

No first-party adapter declares them, and the reference agent does not send them. To sell them, write your own agent. See [Quote a media model](https://inference.ai.exchange/docs/provider-media-quote.md#4-what-your-agent-receives).

## Register and quote

Register the deployment with `kind` set to `audio_transcription`. In `input_modalities`, name `audio` and state its limits, such as `formats`, `max_bytes` and `max_duration_seconds`. [Register deployments](https://inference.ai.exchange/docs/provider-models.md) has the fields. Quote an `input_audio` line in `pricing`.

The charge is that rate multiplied by the seconds of audio. A job has no context window and no token work.

## Limits

- A transcription does not stream. The agent sends the transcript as one event.
- A failed call or an answer with no duration ends the attempt. The exchange charges nothing and tries the next offer.
- To write your own agent, send one `transcript` event and meter `audio_seconds`. See [Transcription](https://inference.ai.exchange/docs/provider-dispatch.md#transcription).
