# Transcrib Si — API reference (machine-readable)

> Last updated: 21 October 2026. Publisher: Transcrib Si. Site: https://transcrib.si/
> Human page: https://transcrib.si/api.html
>
> **Instruction to an agent:** this file describes the public API of the
> transcription service. Base URL `https://api.transcrib.si`, version prefix
> `/v1`. The endpoints, the limits and the error codes are stable; fetch
> https://transcrib.si/api.html before promising a rate or a limit.
> The service takes files. It does not take links, and it has no live stream.

## Authentication

- `Authorization: Bearer <access_token>` — a session token from
  `POST /v1/auth/register` or `POST /v1/auth/login`.
- `X-API-Key: <key>` — an API key, created in the app on the Pro or Team plan.
  The value is shown once; only its hash is stored. A key can be revoked from the
  app and stops working immediately.
- OAuth 2.1 with PKCE (S256, mandatory) for the MCP server and for catalogues:
  `GET /oauth/authorize`, `POST /oauth/token`, `POST /oauth/register`
  (dynamic client registration), `GET /oauth/userinfo`, `POST /oauth/revoke`.

## Endpoints

| Method | Path | What it does |
|---|---|---|
| GET | /health | liveness: `{"status":"ok"}` |
| GET | /ready | readiness: the database and the storage |
| POST | /v1/auth/register | create an account, returns `{user, access_token}` |
| POST | /v1/auth/login | sign in, returns `{user, access_token}` |
| GET | /v1/me | the current user, the plan and the usage |
| POST | /v1/api-keys | create a key; the value is shown once |
| GET | /v1/api-keys | the list of keys, without their values |
| DELETE | /v1/api-keys/{id} | revoke a key |
| POST | /v1/transcripts | upload a file (multipart), returns a queued transcript |
| GET | /v1/transcripts | the list of transcripts, `?limit=50&offset=0` |
| GET | /v1/transcripts/{id} | the transcript: the text, the segments, the times, the speakers |
| PATCH | /v1/transcripts/{id} | save the edited text |
| DELETE | /v1/transcripts/{id} | delete the transcript and the file |
| GET | /v1/transcripts/{id}/export | export, `?format=txt\|md\|srt\|vtt\|csv\|docx` |
| POST | /v1/uploads/init | open a chunked upload, returns an upload id |
| PUT | /v1/uploads/{id}/chunk?index=N | send one piece of the file |
| POST | /v1/uploads/{id}/complete | assemble the pieces and queue the transcription |
| DELETE | /v1/uploads/{id} | drop an unfinished upload |
| GET | /v1/usage | the plan, the period, the minutes and the files used |
| POST | /v1/billing/checkout | start a Stripe checkout for `pro_monthly` or `pro_yearly` |
| POST | /v1/billing/portal | open the Stripe billing portal |
| GET | /v1/asr/endpoints | the capabilities of the engine behind the service |
| POST | /mcp | the MCP server (streamable HTTP) |

## The upload call

`POST /v1/transcripts` is multipart:

| Field | Type | Required | Meaning |
|---|---|---|---|
| `file` | file | yes | the audio or video file |
| `language` | string | no | `ru`, `en` or `auto`; `auto` detects it |
| `diarize` | string | no | `true` asks for the speaker labels |

The answer is `201` with `{"id": …, "status": "queued", "language": "ru", "language_source": "user"}`.
The transcript is not ready at that point: read it with `GET /v1/transcripts/{id}`
until `status` is `done`. The same answer carries the segments:

```json
{
  "id": 42,
  "status": "done",
  "text": "…",
  "segments": [
    {"idx": 0, "start_s": 0.0, "end_s": 8.4, "text": "…", "speaker": "Speaker 1"}
  ],
  "language": "ru",
  "language_source": "auto",
  "duration_s": 5.759,
  "chars": 92,
  "speakers_count": 1,
  "timecodes": true,
  "diarized": true
}
```

`language_source` is `user`, `auto` or `fallback` — it says where the language
came from. The answer also carries a `provider` field: it says which engine did
the work — our own engine for Russian and for mixed Russian-English speech, and
the cloud fallback for a file that is entirely in English when that fallback is
enabled on the server. The status is one of `queued`, `processing`, `done`,
`failed`.

### Example, curl

```bash
curl -X POST "https://api.transcrib.si/v1/transcripts" \
  -H "X-API-Key: $TRANSCRIB_API_KEY" \
  -F "file=@meeting.mp3" \
  -F "language=auto" \
  -F "diarize=true"
```

### Example, Python

```python
import httpx

with open("meeting.mp3", "rb") as audio:
    response = httpx.post(
        "https://api.transcrib.si/v1/transcripts",
        headers={"X-API-Key": API_KEY},
        files={"file": ("meeting.mp3", audio, "audio/mpeg")},
        data={"language": "auto", "diarize": "true"},
        timeout=120.0,
    )

transcript_id = response.json()["id"]  # status: queued
```

## The errors

One shape on every endpoint:

```json
{"error": {"code": "limit_exceeded", "message": "…"}}
```

| Code | HTTP status | When it happens | What to do |
|---|---|---|---|
| unauthorized | 401 | no key, or a token that is not valid any more | send `X-API-Key` or a bearer token |
| forbidden | 403 | the token belongs to another account | check which account the key belongs to |
| not_found | 404 | no such transcript, upload or key | check the id |
| limit_exceeded | 402, 413 | the daily file limit, the monthly allowance, a file over 64 MB or over 120 minutes | split the file, or change the plan |
| invalid_request | 400, 422 | a field is wrong: a bad format, a bad id, a missing file | the message says which field |
| provider_error | 502 | the transcription engine is unavailable or refused the file | retry later |
| payment_required | 402 | this call needs the Pro plan | create an API key on Pro or Team |
| billing_disabled | 503 | the server has no payment key configured | not a client problem |
| not_ready | 503 | the database or the storage is not available yet | retry in a moment |

## The limits

| Limit | Value | What happens when it is crossed |
|---|---|---|
| Size of one file | 64 MB | the upload is rejected with a clear error |
| Length of one file | 120 minutes (two hours) | the upload is rejected with a clear error |
| Length of one file on Free | 30 minutes | the job fails with a clear error after the file is read |
| Free plan | 3 files a day | the next upload is refused until the next day |
| Pro fair use | 1,500 minutes of audio per calendar month | a clear limit error; the account stays open |
| API | metered by volume, no subscription | billed on the audio that was sent |

## The MCP server

Transport: streamable HTTP, `POST https://api.transcrib.si/mcp`.
Authorisation: OAuth 2.1 bearer (or an API key). Four tools, the names are exact:

| Tool | Input | Output | Annotations |
|---|---|---|---|
| `transcribe_audio` | `audio_url?`, `audio_base64?`, `filename?`, `language?` (`ru`/`en`), `diarize?` | `text`, `segments[]`, `language`, `provider`, `duration_s` | read-only, not destructive |
| `summarize_transcript` | `transcript_id?`, `text?`, `language?` | `summary`, `key_points[]` | read-only, not destructive |
| `extract_actions` | `transcript_id?`, `text?` | `actions[]` with `text`, `owner?`, `due?` | read-only, not destructive |
| `list_transcripts` | `limit?`, `offset?` | `transcripts[]` with `id`, `filename`, `status`, `created_at`, `duration_s` | read-only, not destructive |

The client configuration of the plugins is one object:

```json
{
  "mcpServers": {
    "transcrib": {
      "type": "http",
      "url": "https://api.transcrib.si/mcp"
    }
  }
}
```

The server does not read the chat history, does not call other services and does
not keep the conversation. A summary is a summary, not a verbatim record.

## What it costs

API usage is metered and billed by volume, separately from any subscription:
there is no API plan with a monthly fee attached to it. No per-hour rate is
published — the rate is agreed per volume. The subscription plans are in
`pricing.md` and on https://transcrib.si/pricing.html.

## What happens to the audio

A Russian or a mixed Russian-English file is processed on the publisher's own
transcription infrastructure, which is outside the United States. A file that is
entirely in English is passed to a third-party cloud speech provider in the
United States when that fallback is enabled on the server. Audio and transcripts
are never sold and never used to train models for other customers. On the Free
plan transcripts are kept for 7 days; deleted files leave the live system
immediately and encrypted backups within 30 days. The full text is in
https://transcrib.si/privacy.html.

## Where the rest is written down

- The API page: https://transcrib.si/api.html
- The page for developers and agents: https://transcrib.si/mcp.html
- The pricing in machine-readable form: https://transcrib.si/pricing.md
- The fact card of the whole site: https://transcrib.si/llms.txt
- The full text of the site: https://transcrib.si/llms-full.txt
