This document describes the stability guarantees and change process for the OpenTranscription v1 API (/api/v1/*). It is intended for developers building integrations against this API. Read it before you ship; the promises here are what you can rely on.
v1 GuaranteesThe following are contractual surface. They will not change within v1 without a deprecation cycle (see below).
Existing fields keep their name, type, and semantics. New fields may be added at any time (additive changes are non-breaking). Fields will never be renamed or removed without a deprecation window.
Documented status codes stay documented. A 200 today will be a 200 tomorrow. A 403 for an insufficient scope will keep its documented shape.
The four scopes are stable for the lifetime of v1:
| Scope | Purpose |
| ---------------------- | --------------------------------------- |
| transcriptions:read | Read transcription jobs and transcripts |
| transcriptions:write | Create and manage transcription jobs |
| models:read | List and read model metadata |
| usage:read | Read usage and billing data |
New scopes may be added. Existing scope names will not be renamed or removed.
The { error: string } envelope is stable. Fields such as required that appear on specific error types (e.g., scope errors) will keep their meaning. Additional fields (e.g., code, details) may be added in future.
Example 403 response:
{ "error": "Insufficient scope", "required": "transcriptions:write" }
Do not branch on the error string — it is human-readable and may be reworded. Branch on HTTP status code and structured fields like required.
These headers are stable:
| Header | Direction | Meaning |
| ----------------------------- | --------- | ------------------------------------ |
| Authorization: Bearer <key> | Request | Authentication |
| X-RateLimit-Limit | Response | Requests allowed per window |
| X-RateLimit-Remaining | Response | Requests remaining in current window |
| X-RateLimit-Reset | Response | Unix timestamp when window resets |
New headers may be added. Existing headers will not be renamed.
Bearer token authentication using keys with the ot_ prefix is stable for the life of v1. The key format (ot_live_... / ot_test_...) is also stable.
Paths under /api/v1/* keep their semantics. New paths may be added; existing paths will not be moved or removed within v1.
Do not build implicit dependencies on these — they are not guaranteed.
Latency. Response time targets are covered as aspirational values in slo.md, not contractual guarantees.
Exact error message wording. The error field is a human-readable string. It may be reworded, improved, or localized at any time. Always branch on structured fields (status code, required, code) — never on the string value.
Undocumented fields. Any field present in a response but absent from the OpenAPI spec is internal. It may change or disappear without notice.
Job transition timing. When a job moves from uploaded to processing to completed is not contractual. Poll for status or use webhooks (when available) rather than assuming timing.
Array ordering. Unless a response is explicitly documented as ordered, do not assume a stable sort order.
Breaking changes — removing a field, renaming a field, changing a type, or changing the semantics of a status code — do NOT ship to /api/v1/* in place. They go to /api/v2/*. Integrators opt in to v2 by changing URLs.
Sunset header appears on the deprecated endpoint with the planned removal date (ISO 8601 / RFC 8594 format).Deprecation: true header appears alongside it.Example response headers on a deprecated endpoint:
Sunset: 2026-09-01T00:00:00Z
Deprecation: true
90 days from the first Sunset header appearing to the endpoint being removed.
A vulnerability patch may require a shorter window. In such cases we will still send email notification and publish a changelog entry — we will never silently remove or change an endpoint.
These can ship to v1 at any time without versioning or advance notice:
All v1 operations are under /api/v1/*. There is no Api-Version header.
When v2 ships, it will be under /api/v2/*. You will need to consciously opt in by updating your base URL. There is no silent migration.
A formal changelog is planned and will be linked here when available. In the interim, breaking change notices and deprecation announcements are published to the status page.
<!-- TODO: Update with actual status page URL once status.opentranscription.io CNAME is provisioned -->To receive notifications:
For general API questions, open a support ticket at https://opentranscription.io/support.
Enterprise customers with SLA agreements have a dedicated account manager for contract-level questions. Contact details are in your onboarding email.