If you need to transcribe audio programmatically – whether for a SaaS product, internal tool, or automated pipeline – DeepScript provides a REST API that handles the heavy lifting. Upload a file, get a transcript back. No ML infrastructure to manage, no model hosting to worry about.
This guide walks you through authentication, file upload, status polling, and result retrieval with working code examples in cURL, Python, and JavaScript.
Full API reference: api.deepscript.com/docs
Authentication
All API requests require an API key. You can generate one in your DeepScript dashboard under Settings > API Keys.
Include the key in the Authorization header of every request:
Authorization: Bearer YOUR_API_KEYKeep your API key secret. Do not commit it to version control or expose it in client-side code. Use environment variables or a secrets manager.
Core Workflow
The transcription workflow follows three steps:
- Upload an audio or video file to create a transcription job
- Poll
/statusuntil processing completes (or use webhooks) - Retrieve the finished transcript from the detail endpoint
Two conventions to know before you wire anything up: every payload sits inside a data object, and ids are UUIDs.
Upload a File
Send a POST request with your file to create a new transcription job.
cURL
curl -X POST https://api.deepscript.com/v1/transcriptions \
-H "Authorization: Bearer $DEEPSCRIPT_API_KEY" \
-F "file=@meeting-recording.mp3" \
-F "model=standard" \
-F "language=auto"Python
import requests
API_KEY = os.environ["DEEPSCRIPT_API_KEY"]
BASE_URL = "https://api.deepscript.com/v1"
def create_transcription(file_path, model="standard", language="auto"):
with open(file_path, "rb") as f:
response = requests.post(
f"{BASE_URL}/transcriptions",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": f},
data={"model": model, "language": language},
)
response.raise_for_status()
return response.json()["data"]
job = create_transcription("meeting-recording.mp3")
print(f"Job created: {job['id']}")JavaScript (Node.js)
import fs from "fs";
import FormData from "form-data";
const API_KEY = process.env.DEEPSCRIPT_API_KEY;
const BASE_URL = "https://api.deepscript.com/v1";
async function createTranscription(filePath, model = "standard", language = "auto") {
const form = new FormData();
form.append("file", fs.createReadStream(filePath));
form.append("model", model);
form.append("language", language);
const response = await fetch(`${BASE_URL}/transcriptions`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
...form.getHeaders(),
},
body: form,
});
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
const { data } = await response.json();
return data;
}
const job = await createTranscription("meeting-recording.mp3");
console.log(`Job created: ${job.id}`);Response
The upload answers 202 Accepted as soon as the file is queued:
{
"data": {
"id": "3f7c1e42-9b18-4a6d-8f21-6c0b5d9e77a4",
"status": "queued"
}
}Poll for Status
Transcription takes roughly 20-50% of the audio duration, depending on file length and the model selected. Poll the dedicated status endpoint until the job completes: it returns only id, status and progress, which makes it roughly ten times cheaper than the detail endpoint. Recommended interval is 2 to 5 seconds.
cURL
curl "https://api.deepscript.com/v1/transcriptions/$JOB_ID/status" \
-H "Authorization: Bearer $DEEPSCRIPT_API_KEY"Python
import time
def wait_for_transcription(job_id, interval=5):
while True:
response = requests.get(
f"{BASE_URL}/transcriptions/{job_id}/status",
headers={"Authorization": f"Bearer {API_KEY}"},
)
response.raise_for_status()
data = response.json()["data"]
if data["status"] == "completed":
return data
if data["status"] == "failed":
raise RuntimeError("Transcription failed")
print(f"{data['progress']} %")
time.sleep(interval)
wait_for_transcription(job["id"])JavaScript (Node.js)
async function waitForTranscription(jobId, interval = 5000) {
while (true) {
const response = await fetch(`${BASE_URL}/transcriptions/${jobId}/status`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!response.ok) throw new Error(`Poll failed: ${response.status}`);
const { data } = await response.json();
if (data.status === "completed") return data;
if (data.status === "failed") throw new Error("Transcription failed");
await new Promise((resolve) => setTimeout(resolve, interval));
}
}
await waitForTranscription(job.id);Response
{
"data": {
"id": "3f7c1e42-9b18-4a6d-8f21-6c0b5d9e77a4",
"status": "processing",
"progress": 64
}
}If you are driving a progress bar, use the SSE stream at /v1/transcriptions/{id}/events instead: one open connection, an event on every change, no interval to pick.
Get the Transcript
Once the status flips to completed, the detail endpoint returns the full record. Fetch it exactly once – it carries the word-level list and is heavy by design.
cURL
curl "https://api.deepscript.com/v1/transcriptions/$JOB_ID" \
-H "Authorization: Bearer $DEEPSCRIPT_API_KEY"Python
def get_transcription(job_id):
response = requests.get(
f"{BASE_URL}/transcriptions/{job_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
response.raise_for_status()
return response.json()["data"]
detail = get_transcription(job["id"])
print(detail["resultText"])JavaScript (Node.js)
async function getTranscription(jobId) {
const response = await fetch(`${BASE_URL}/transcriptions/${jobId}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!response.ok) throw new Error(`Fetch failed: ${response.status}`);
const { data } = await response.json();
return data;
}
const detail = await getTranscription(job.id);
console.log(detail.resultText);Response, abridged
{
"data": {
"id": "3f7c1e42-9b18-4a6d-8f21-6c0b5d9e77a4",
"status": "completed",
"language": "en",
"detectedLanguage": "en",
"duration": 1847,
"wordCount": 4021,
"speakerCount": 3,
"cost": 0.09,
"resultText": "Welcome everyone to the quarterly review. Let's start with…",
"resultJson": {
"words": [
{ "word": "Welcome", "start": 0.0, "end": 0.42, "speaker": 0 },
{ "word": "everyone", "start": 0.42, "end": 0.91, "speaker": 0 }
]
}
}
}resultText is the running text, resultJson.words the time-resolved word list with speaker assignment. Search and indexing only need the text; subtitles and click-to-seek need the words.
Subtitles and other formats
You do not have to assemble subtitles from the timestamps yourself. The export endpoint renders the finished transcription into the format you ask for:
curl "https://api.deepscript.com/v1/transcriptions/$JOB_ID/export?format=srt" \
-H "Authorization: Bearer $DEEPSCRIPT_API_KEY" \
-o subtitles.srtAvailable formats are txt, srt, vtt, json and docx. It only works on completed transcriptions; otherwise the API answers with the problem type not-ready.
Models
DeepScript offers two transcription models:
| Model | Use Case | Speed | Accuracy |
|---|---|---|---|
standard | Clean audio, meetings, podcasts | Faster | High |
premium | Noisy environments, accents, technical content | Slower | Highest |
Pass the model parameter during upload. Default is standard.
The premium model is recommended for recordings with background noise, overlapping speakers, heavy accents, or domain-specific terminology.
Language Support
DeepScript supports 99 languages. Set language to a BCP-47 code (e.g., en, de, fr, ja) or use auto for automatic detection.
Auto-detection works well for single-language recordings. If you know the language in advance, specifying it explicitly can improve accuracy slightly.
Webhooks
Instead of polling, register a webhook endpoint once – not per upload:
curl -X POST https://api.deepscript.com/v1/webhooks \
-H "Authorization: Bearer $DEEPSCRIPT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/api/transcription-callback",
"events": ["transcription.completed", "transcription.failed"]
}'The response carries the signing secret, exactly once: there is no recovery flow. Every delivery is signed with HMAC-SHA256 over the body, and you verify it with that secret. A webhook handler without signature verification is an open endpoint where anyone can shout "done".
When a job finishes, DeepScript posts the event and the transcription id; your server then fetches the full record from the detail endpoint.
Custom Vocabulary
For domain-specific terms – product names, medical terminology, legal jargon, company-internal acronyms – you can pass a custom vocabulary list to improve recognition accuracy.
curl -X POST https://api.deepscript.com/v1/transcriptions \
-H "Authorization: Bearer $DEEPSCRIPT_API_KEY" \
-F "file=@recording.mp3" \
-F "model=premium" \
-F 'vocabulary=["DeepScript", "Hetzner", "DSGVO", "Kubernetes"]'The field is called vocabulary and takes a JSON array or a comma-separated string. If you need the same list repeatedly, store it once under /v1/vocabularies and pass only the vocabulary_id afterwards.
The engine biases toward these terms when the audio is ambiguous, which is almost always the case for proper nouns and for technical terms that no general-purpose dictionary contains.
Speaker count
Diarization is included in both models. If you know how many people are speaking, say so:
curl -X POST https://api.deepscript.com/v1/transcriptions \
-H "Authorization: Bearer $DEEPSCRIPT_API_KEY" \
-F "file=@interview.mp3" \
-F "model=premium" \
-F "num_speakers=2"num_speakers pins the count. Alternatively min_speakers and max_speakers bound it, and those two always travel together. For a two-person interview the fixed count is the single most effective lever against split speakers.
Rate Limits and Pricing
API usage is billed based on audio duration. Check the pricing page for current rates. Rate limits depend on your plan – the API returns 429 Too Many Requests if you exceed them, along with a Retry-After header.
Privacy
All API processing happens on dedicated servers in Germany (Hetzner). No audio data is sent to third-party AI providers. Files are deleted after processing. DeepScript provides a Data Processing Agreement (AVV) for business customers.
This makes the API suitable for processing sensitive audio – legal recordings, medical dictations, HR interviews – where GDPR compliance is mandatory.
Next Steps
- Read the full API reference at api.deepscript.com/docs
- Generate your API key in the DeepScript dashboard
- Explore the pricing plans for API usage
- Contact support@deepscript.com for enterprise needs or custom integrations