Poll with backoff
Poll job status every 2–5 seconds. Use exponential backoff for longer-running jobs. Most jobs under 1 hour complete within 1–5 minutes.
Everything you need to integrate audio transcription into your application. Submit audio, poll for results, and download structured transcripts with speaker labels, PII redaction, and AI-powered insights.
Get your first transcription running in under a minute.
Sign up at tuplets.ai/signup, verify your email, and generate an API key from your dashboard settings. Keys are prefixed with tb_ and are shown only once.
Pass your API key as a Bearer token in the Authorization header on every request.
export TUPLETS_API_KEY="tb_your_key_here"
# Verify the key works
curl -H "Authorization: Bearer $TUPLETS_API_KEY" \
https://api.tuplets.ai/healthUpload an audio file directly, or point to a remote URL. We support MP3, WAV, M4A, FLAC, OGG, AAC, WMA, WebM, and Opus.
# Upload a local file
curl -X POST https://api.tuplets.ai/jobs \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-F "audio_file=@interview.mp3" \
-F "language=en" \
-F "diarization=true"
# Or submit a remote URL
curl -X POST https://api.tuplets.ai/jobs \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-F "remote_url=https://storage.example.com/recording.mp3" \
-F "language=en"# Poll job status
curl https://api.tuplets.ai/jobs/{job_id} \
-H "Authorization: Bearer $TUPLETS_API_KEY"
# Download completed transcript JSON
curl https://api.tuplets.ai/jobs/{job_id}/download \
-H "Authorization: Bearer $TUPLETS_API_KEY"All API requests require authentication via an API key or a session cookie.
Generate API keys from your account settings. Keys begin with tb_ and are 43 characters total.
Include the key in the Authorization header as a Bearer token:
curl -H "Authorization: Bearer tb_your_key_here" \
https://api.tuplets.ai/jobs| Endpoint | Method | Description |
|---|---|---|
| /account/api-keys | POST | Create a new API key |
| /account/api-keys | GET | List active API keys |
| /account/api-keys/{key_id}/rotate | POST | Rotate (replace) an API key |
| /account/api-keys/{key_id} | DELETE | Revoke an API key |
# Create a new API key
curl -X POST https://api.tuplets.ai/account/api-keys \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "My Integration Key"}'Rotate keys regularly and revoke compromised keys immediately.
POST /account/api-keys/{key_id}/rotate.DELETE /account/api-keys/{key_id}.Base URL: https://api.tuplets.ai — All endpoints return JSON.
Submit audio for processing. You must provide exactly one of: audio_file, remote_url, or uploaded_audio_key.
/jobsSubmit a new transcription job| Parameter | Type | Required | Description |
|---|---|---|---|
| audio_file | file | conditional | Audio file (MP3, WAV, M4A, FLAC, OGG, AAC, WMA, WebM, Opus). Max 500 MB. |
| remote_url | string | conditional | Public HTTP/HTTPS URL pointing to an audio file. |
| uploaded_audio_key | string | conditional | Object key from a browser upload. Must be paired with uploaded_audio_token. |
| uploaded_audio_token | string | conditional | Upload token from the browser upload flow. |
| language | string | optional | Language code (ISO 639-1). Default: auto (automatic detection). |
| diarization | boolean | optional | Enable speaker diarization (separate speakers). Default: false. |
| pii_processing | boolean | optional | Enable PII redaction. Default: false. |
| insights | boolean | optional | Enable AI insights (summary, sentiment, keywords, topics). Default: false. |
# Upload file with all options
curl -X POST https://api.tuplets.ai/jobs \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-F "audio_file=@call_recording.mp3" \
-F "language=en" \
-F "diarization=true" \
-F "pii_processing=true" \
-F "insights=true"
# Remote URL
curl -X POST https://api.tuplets.ai/jobs \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-F "remote_url=https://example.com/audio.mp3" \
-F "language=auto"Response
{
"status": "accepted"
}Retrieve the current status and result of a transcription job.
/jobs/{job_id}Get a single job by IDcurl https://api.tuplets.ai/jobs/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $TUPLETS_API_KEY"Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"result": {
"text": "Hello, this is a transcript of the audio…",
"segments": [
{
"start": 0,
"end": 2.5,
"text": "Hello",
"speaker": "SPEAKER_00"
},
{
"start": 2.5,
"end": 5,
"text": "this is a transcript",
"speaker": "SPEAKER_01"
}
],
"summary": "A brief conversation about…",
"sentiment": "positive",
"keywords": [
"transcription",
"audio",
"AI"
]
},
"error_message": null,
"audio_duration_seconds": 120.5,
"diarization": true,
"pii_processing": false,
"insights": true,
"estimated_cost_usd": 0.015,
"billed_cost_usd": 0.015,
"billing_status": "charged",
"source_type": "upload",
"result_download_available": true,
"source_audio_available": true,
"cancel_token": null,
"created_at": "2025-03-15T10:30:00Z",
"started_at": "2025-03-15T10:30:02Z",
"completed_at": "2025-03-15T10:31:45Z",
"runtime_ms": 103000
}| Field | Type | Description |
|---|---|---|
| id | UUID | Unique job identifier |
| status | string | queued | running | completed | failed |
| result | object | null | Full transcript result (when completed) |
| error_message | string | null | Error detail if failed |
| audio_duration_seconds | number | null | Detected audio duration |
| diarization | boolean | Whether speaker diarization was requested |
| pii_processing | boolean | Whether PII processing was requested |
| insights | boolean | Whether AI insights were requested |
| estimated_cost_usd | number | null | Pre-run cost estimate |
| billed_cost_usd | number | null | Actual amount charged |
| billing_status | string | null | pending | charged | skipped |
| result_download_available | boolean | Whether JSON download is available |
| cancel_token | string | null | Token to cancel this job (queued/running only) |
| created_at | datetime | Job creation timestamp |
| completed_at | datetime | null | Job completion timestamp |
| runtime_ms | number | null | Processing time in milliseconds |
Browse transcription jobs with optional status filtering.
/jobsList jobs for the authenticated account| Query Parameter | Type | Required | Description |
|---|---|---|---|
| status | string | optional | Filter by status: queued, running, completed, or failed |
| limit | integer | optional | Max results (1–100). Default: 20. |
# List recent completed jobs
curl "https://api.tuplets.ai/jobs?status=completed&limit=10" \
-H "Authorization: Bearer $TUPLETS_API_KEY"{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"audio_duration_seconds": 120.5,
"diarization": true,
"insights": false,
"estimated_cost_usd": 0.012,
"billed_cost_usd": 0.012,
"created_at": "2025-03-15T10:30:00Z"
}
],
"total_items": 1,
"status_filter": "completed"
}Cancel a queued or running job. Two methods: by ID (authenticated) or by cancel token (shared).
/jobs/{job_id}Cancel a jobcurl -X DELETE https://api.tuplets.ai/jobs/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $TUPLETS_API_KEY"/jobs/cancelCancel a job using a shared cancel tokencurl -X POST https://api.tuplets.ai/jobs/cancel \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"cancel_token": "<cancel_token_from_job_status>"}'Download the full transcript JSON for a completed job. Results are available for 7 days after completion.
/jobs/{job_id}/downloadDownload transcript JSON as an attachmentcurl https://api.tuplets.ai/jobs/550e8400-e29b-41d4-a716-446655440000/download \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-o transcript.jsonFor large files (up to 500 MB), use the direct-to-storage upload flow to avoid proxying through your server.
The browser upload flow has three steps:
POST /jobs/upload-target.uploaded_audio_key and uploaded_audio_token./jobs/upload-targetGet a signed upload URLcurl -X POST https://api.tuplets.ai/jobs/upload-target \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "meeting.mp3", "content_type": "audio/mpeg"}'# Upload directly using the signed URL
curl -X PUT "{upload_url}" \
-H "Content-Type: audio/mpeg" \
--data-binary @meeting.mp3curl -X POST https://api.tuplets.ai/jobs \
-H "Authorization: Bearer $TUPLETS_API_KEY" \
-F "uploaded_audio_key={object_key}" \
-F "uploaded_audio_token={upload_token}" \
-F "language=en" \
-F "diarization=true"Supported input formats and file constraints for transcription jobs.
| Format | Extension | Notes |
|---|---|---|
| MP3 | .mp3 | Most common. Good balance of quality and size. |
| WAV | .wav | Uncompressed. Best quality but largest size. |
| FLAC | .flac | Lossless compression. High quality. |
| OGG | .ogg | Open format. Good for web use. |
| M4A | .m4a | Common in Apple ecosystem. |
| AAC | .aac | Advanced Audio Codec. |
| WMA | .wma | Windows Media Audio. |
| WebM | .webm | Web-optimized format. |
| Opus | .opus | Low latency, high compression. |
Tuplets supports 98 languages using OpenAI Whisper. Set language to auto for automatic detection, or specify a code for best accuracy.
Specify language using ISO 639-1 two-letter codes (e.g., en for English, es for Spanish, ja for Japanese). Use auto or omit the parameter for automatic language detection.
af, am, ar, as, az, ba, be, bg, bn, bo, br, bs, ca, cs, cy, da, de, el, en, es, et, eu, fa, fi, fo, fr, gl, gu, ha, haw, hi, hr, hu, hy, id, is, it, ja, jw, ka, kk, km, kn, ko, la, lb, ln, lo, lt, lv, mg, mi, mk, ml, mn, mr, ms, mt, my, ne, nl, nn, no, oc, pa, pl, ps, pt, ro, ru, sa, sd, si, sk, sl, sn, so, sr, su, sv, sw, ta, te, tg, th, tk, tl, tr, tt, uk, ur, uz, vi, yi, yo, zh
You are charged per-second of audio processed. New accounts receive $2.50 in free credits to get started.
| Feature | Rate | Required |
|---|---|---|
| Transcription | $0.22 / hour | Always included |
| Speaker Diarization | $0.08 / hour | Optional |
| PII Processing | $0.06 / hour | Optional |
| Business Insights | $0.08 / hour | Optional |
A 1-hour recording (3600 seconds) with diarization and insights enabled:
{
"duration_seconds": 3600,
"duration_hours": 1,
"line_items": [
{
"feature_key": "transcription",
"display_name": "Transcription",
"rate_usd_per_hour": 0.22,
"amount_usd": 0.22
},
{
"feature_key": "diarization",
"display_name": "Speaker diarization",
"rate_usd_per_hour": 0.08,
"amount_usd": 0.08
},
{
"feature_key": "insights",
"display_name": "Business insights",
"rate_usd_per_hour": 0.08,
"amount_usd": 0.08
}
],
"total_usd": 0.38
}You can estimate cost before submitting by calculating total = transcription + (diarization ? 0.08 : 0) + (pii ? 0.06 : 0) + (insights ? 0.08 : 0) × hours.
Rate limits protect the platform from abuse. Limits apply per IP address and per user account.
| Scope | Limit | Window |
|---|---|---|
| Global (IP) | 300 requests | 5 minutes |
| Job creation (IP) | 30 requests | 1 hour |
| Job creation (user) | 10 requests | 1 hour |
| Job creation burst (user) | 3 requests | 5 minutes |
| Download (IP) | 120 requests | 1 hour |
| Download (user) | 40 requests | 15 minutes |
The API returns 429 Too Many Requests. Check the Retry-After header and back off accordingly. Implement exponential backoff in your integration.
Every error response includes a detail field explaining what went wrong and how to fix it.
| Code | Label | Detail | Fix |
|---|---|---|---|
400 | Bad Request | Invalid input or missing required field. | Check your request parameters. |
401 | Unauthorized | Missing or invalid API key / session. | Provide a valid Authorization: Bearer header. |
402 | Insufficient Credit | Account balance is too low for the estimated cost. | Top up your account and retry. |
403 | Forbidden | Email not verified or action not allowed. | Verify your email address first. |
404 | Not Found | The requested resource does not exist. | Check the job ID or resource path. |
409 | Conflict | Concurrent job limit reached or resource unavailable. | Wait for active jobs to complete. |
410 | Gone | Result download is no longer available. | Download results within the 7-day retention window. |
429 | Rate Limited | Too many requests in the current window. | Respect retry-after headers and back off. |
503 | Service Unavailable | Processing capacity temporarily unavailable. | Retry after a short delay. |
Error responses follow this format:
{
"detail": "You do not have enough credit for this job."
}Recommendations for building a reliable integration.
Poll job status every 2–5 seconds. Use exponential backoff for longer-running jobs. Most jobs under 1 hour complete within 1–5 minutes.
Save the cancel_token from job responses if you need to implement user-facing cancellation without re-authentication.
Files over 25 MB should use the browser upload flow. This avoids double-proxying through your server and is significantly faster.
Automatic detection is accurate, but specifying the language code yields better results — especially for code-switching or accented speech.
Transcript JSON downloads are available for up to 7 days after job completion. Download and archive results you need to keep.
Check for 429 responses and implement retry logic with exponential backoff. Use the Retry-After header to determine wait time.