Speech-to-Text API
Turn audio and video into text from your own code. One key gives you the whole pipeline: any input format, automatic language detection (~99 languages), long-file chunking, and LLM post-processing — clean text, summaries, action items, translation.
Quick start
1. Sign up and confirm your email. 2. In your account, open “API keys” and create a key (shown once). 3. Send your first request:
Upload a file and wait for the result:
curl -X POST https://oratext.com/api/v1/transcriptions \
-H "Authorization: Bearer ora_sk_YOUR_KEY" \
-F "file=@meeting.mp3" \
-F "wait=true"
With wait=true the server holds the connection for up to ~90 seconds and returns the finished text in one request — enough for most files. For long recordings use the asynchronous flow below.
Authentication
Every request needs the header Authorization: Bearer ora_sk_… . Keys are created in your account and can be revoked at any time. Keep the key secret: anyone who has it spends your minutes.
Authorization: Bearer ora_sk_YOUR_KEY
Create a transcription
POST /api/v1/transcriptions
POST /api/v1/transcriptions accepts either multipart/form-data with a file, or JSON/form with a url — we download the file ourselves (public hosts, ports 80/443, up to 3 redirects). Exactly one source per request.
| Parameter | Description |
|---|---|
file | Audio or video file (multipart/form-data). MP3, WAV, M4A, OGG, MP4, MOV and most other formats. |
url | Direct http(s) link to the file instead of uploading it. |
level | Processing level: standard, premium or ultra. Defaults to the best level of your plan. Higher levels use stronger models. |
mode | Optional post-processing applied right after transcription: clean (remove filler words), summary, tasks or translate. The result is returned in mode_text next to the raw text. |
target_lang | Target language for mode=translate, e.g. “English” or “Español”. |
wait | true — hold the request until the result is ready (up to ~90 s). If time runs out you get 202 with the id — poll it as usual. |
Or pass a link — with a summary ordered right away:
curl -X POST https://oratext.com/api/v1/transcriptions \
-H "Authorization: Bearer ora_sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/podcast.mp3", "mode": "summary", "wait": "true"}'
Success codes: 201 — task created (no wait), 200 — wait finished with the result, 202 — wait timed out, keep polling by id.
Get the result
GET /api/v1/transcriptions/{id}
Poll GET /api/v1/transcriptions/{id} every 1–3 seconds. Status values: queued → processing → done; error means processing failed (minutes are not lost — the job did not complete), rejected means a business rule stopped it (quota, duration).
Check status / fetch the result:
curl -H "Authorization: Bearer ora_sk_YOUR_KEY" \
https://oratext.com/api/v1/transcriptions/JOB_ID
Response when done:
{
"id": "3f2b8c1e-5a70-4a3e-9c0f-1d2e3f4a5b6c",
"status": "done",
"level": "standard",
"duration_sec": 184.2,
"language": "ru",
"mode": "summary",
"text": "…full transcript…",
"mode_text": "…summary…"
}
Post-process the text
POST /api/v1/transcriptions/{id}/process
Any finished transcription can be re-processed without new minutes: POST /api/v1/transcriptions/{id}/process with mode and, for translation, target_lang. Up to 20 processing calls per transcription.
curl -X POST https://oratext.com/api/v1/transcriptions/JOB_ID/process \
-H "Authorization: Bearer ora_sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"mode": "translate", "target_lang": "English"}'
Check your quota
GET /api/v1/usage
GET /api/v1/usage returns your plan, the limit, used and remaining minutes, and when the quota resets. Call it before sending big files.
{
"plan": "free",
"period": "day",
"limit_minutes": 5.0,
"used_minutes": 1.2,
"remaining_minutes": 3.8,
"resets_at": "2026-08-06T00:00:00+00:00"
}
Python example:
import requests, time
API = "https://oratext.com/api/v1"
HEADERS = {"Authorization": "Bearer ora_sk_YOUR_KEY"}
with open("meeting.mp3", "rb") as f:
r = requests.post(f"{API}/transcriptions", headers=HEADERS,
files={"file": f}, data={"mode": "summary", "wait": "true"})
job = r.json()
if not r.ok:
raise SystemExit(job["error"]["message"])
while job["status"] not in ("done", "error", "rejected"):
time.sleep(2)
job = requests.get(f"{API}/transcriptions/{job['id']}", headers=HEADERS).json()
if job["status"] == "done":
print(job["text"])
print(job.get("mode_text"))
else:
print("failed:", job["error"]["message"])
JavaScript (Node 18+) example:
const API = "https://oratext.com/api/v1";
const headers = { Authorization: "Bearer ora_sk_YOUR_KEY" };
const res = await fetch(`${API}/transcriptions`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://example.com/podcast.mp3", wait: "true" }),
});
let job = await res.json();
if (!res.ok) throw new Error(job.error.message);
while (!["done", "error", "rejected"].includes(job.status)) {
await new Promise(r => setTimeout(r, 2000));
job = await (await fetch(`${API}/transcriptions/${job.id}`, { headers })).json();
}
console.log(job.status === "done" ? job.text : job.error.message);
Limits
- Minutes are shared with your plan: Free — 5 min/day, Premium — 500 min/month, Ultra — 1000 min/month. A file that does not fit into the remaining minutes is rejected before processing.
- One file: up to 200 MB and up to 120 minutes of audio.
- Rate limits per key: 10 transcription/processing requests per minute, 60 status requests per minute.
- Up to 5 active keys per account; revoke unused ones in your account.
Errors
Errors come as JSON: {"error": {"code": "…", "message": "…"}}. The main codes:
| HTTP | Description |
|---|---|
400 | bad_request / invalid_level / invalid_mode / url_invalid / url_blocked / url_failed — a parameter or the url is wrong; details in message. |
401 | Missing, invalid or revoked API key. |
402 | quota_exceeded — not enough minutes left on the plan; the response includes remaining_minutes. |
403 | email_unverified, level_not_allowed or llm_limit — confirm your email; the requested level is above your plan; or the 20-processing cap for that transcription is used up. |
404 | not_found — no transcription with this id on this API key. |
409 | not_ready — the transcription is not finished yet; wait for status done. |
413 | file_too_large / too_long — the file exceeds the size or duration limit. |
415 | unsupported_media — we could not decode audio from the file. |
429 | rate_limited — too many requests per minute; slow down and retry. |
502 | llm_failed — text processing failed; retry later. |
Questions?
Write to us in Telegram: @oratextbot — we answer quickly and are happy to help with integration.