Version 1.0 · REST API

API Documentation

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.

Quick Start

Get your first transcription running in under a minute.

1. Create an account and get your API key

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.

2. Set your API key

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/health

3. Submit audio for transcription

Upload 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"

4. Poll for completion and download

# 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"

Authentication

All API requests require authentication via an API key or a session cookie.

API Keys

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
EndpointMethodDescription
/account/api-keysPOSTCreate a new API key
/account/api-keysGETList active API keys
/account/api-keys/{key_id}/rotatePOSTRotate (replace) an API key
/account/api-keys/{key_id}DELETERevoke 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"}'

Key Rotation & Security

Rotate keys regularly and revoke compromised keys immediately.

  • Keys are hashed using bcrypt before storage — we never store raw keys.
  • The raw key is shown only once at creation time.
  • Rotate keys via POST /account/api-keys/{key_id}/rotate.
  • Revoke keys via DELETE /account/api-keys/{key_id}.
  • Each key is scoped to a single account.

API Reference

Base URL: https://api.tuplets.ai — All endpoints return JSON.

Create a Transcription Job

Submit audio for processing. You must provide exactly one of: audio_file, remote_url, or uploaded_audio_key.

POST/jobsSubmit a new transcription job
ParameterTypeRequiredDescription
audio_filefileconditionalAudio file (MP3, WAV, M4A, FLAC, OGG, AAC, WMA, WebM, Opus). Max 500 MB.
remote_urlstringconditionalPublic HTTP/HTTPS URL pointing to an audio file.
uploaded_audio_keystringconditionalObject key from a browser upload. Must be paired with uploaded_audio_token.
uploaded_audio_tokenstringconditionalUpload token from the browser upload flow.
languagestringoptionalLanguage code (ISO 639-1). Default: auto (automatic detection).
diarizationbooleanoptionalEnable speaker diarization (separate speakers). Default: false.
pii_processingbooleanoptionalEnable PII redaction. Default: false.
insightsbooleanoptionalEnable 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"
}

Get Job Status

Retrieve the current status and result of a transcription job.

GET/jobs/{job_id}Get a single job by ID
curl 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
}
FieldTypeDescription
idUUIDUnique job identifier
statusstringqueued | running | completed | failed
resultobject | nullFull transcript result (when completed)
error_messagestring | nullError detail if failed
audio_duration_secondsnumber | nullDetected audio duration
diarizationbooleanWhether speaker diarization was requested
pii_processingbooleanWhether PII processing was requested
insightsbooleanWhether AI insights were requested
estimated_cost_usdnumber | nullPre-run cost estimate
billed_cost_usdnumber | nullActual amount charged
billing_statusstring | nullpending | charged | skipped
result_download_availablebooleanWhether JSON download is available
cancel_tokenstring | nullToken to cancel this job (queued/running only)
created_atdatetimeJob creation timestamp
completed_atdatetime | nullJob completion timestamp
runtime_msnumber | nullProcessing time in milliseconds

List Jobs

Browse transcription jobs with optional status filtering.

GET/jobsList jobs for the authenticated account
Query ParameterTypeRequiredDescription
statusstringoptionalFilter by status: queued, running, completed, or failed
limitintegeroptionalMax 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 Job

Cancel a queued or running job. Two methods: by ID (authenticated) or by cancel token (shared).

Cancel by Job ID

DELETE/jobs/{job_id}Cancel a job
curl -X DELETE https://api.tuplets.ai/jobs/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer $TUPLETS_API_KEY"

Cancel by Token

POST/jobs/cancelCancel a job using a shared cancel token
curl -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 Transcript

Download the full transcript JSON for a completed job. Results are available for 7 days after completion.

GET/jobs/{job_id}/downloadDownload transcript JSON as an attachment
curl https://api.tuplets.ai/jobs/550e8400-e29b-41d4-a716-446655440000/download \
  -H "Authorization: Bearer $TUPLETS_API_KEY" \
  -o transcript.json

Browser Upload Flow

For 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:

  1. Request an upload target via POST /jobs/upload-target.
  2. Upload the file directly to the returned URL using a PUT request.
  3. Submit the job referencing uploaded_audio_key and uploaded_audio_token.

Step 1: Get an upload target

POST/jobs/upload-targetGet a signed upload URL
curl -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"}'

Step 2: Upload the file directly

# Upload directly using the signed URL
curl -X PUT "{upload_url}" \
  -H "Content-Type: audio/mpeg" \
  --data-binary @meeting.mp3

Step 3: Submit the job

curl -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"

Audio Formats & Constraints

Supported input formats and file constraints for transcription jobs.

FormatExtensionNotes
MP3.mp3Most common. Good balance of quality and size.
WAV.wavUncompressed. Best quality but largest size.
FLAC.flacLossless compression. High quality.
OGG.oggOpen format. Good for web use.
M4A.m4aCommon in Apple ecosystem.
AAC.aacAdvanced Audio Codec.
WMA.wmaWindows Media Audio.
WebM.webmWeb-optimized format.
Opus.opusLow latency, high compression.

Constraints

  • Minimum audio duration: 45 seconds
  • Maximum audio duration: 20 hours
  • Maximum file size (direct upload): 500 MB
  • Remote URLs must be publicly accessible HTTP/HTTPS endpoints

Supported Languages

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.

Browse all 98 supported language codes

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

Pricing

You are charged per-second of audio processed. New accounts receive $2.50 in free credits to get started.

FeatureRateRequired
Transcription$0.22 / hourAlways included
Speaker Diarization$0.08 / hourOptional
PII Processing$0.06 / hourOptional
Business Insights$0.08 / hourOptional

Cost estimation example

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

Rate limits protect the platform from abuse. Limits apply per IP address and per user account.

ScopeLimitWindow
Global (IP)300 requests5 minutes
Job creation (IP)30 requests1 hour
Job creation (user)10 requests1 hour
Job creation burst (user)3 requests5 minutes
Download (IP)120 requests1 hour
Download (user)40 requests15 minutes

When rate limited

The API returns 429 Too Many Requests. Check the Retry-After header and back off accordingly. Implement exponential backoff in your integration.

Error Codes

Every error response includes a detail field explaining what went wrong and how to fix it.

CodeLabelDetailFix
400Bad RequestInvalid input or missing required field.Check your request parameters.
401UnauthorizedMissing or invalid API key / session.Provide a valid Authorization: Bearer header.
402Insufficient CreditAccount balance is too low for the estimated cost.Top up your account and retry.
403ForbiddenEmail not verified or action not allowed.Verify your email address first.
404Not FoundThe requested resource does not exist.Check the job ID or resource path.
409ConflictConcurrent job limit reached or resource unavailable.Wait for active jobs to complete.
410GoneResult download is no longer available.Download results within the 7-day retention window.
429Rate LimitedToo many requests in the current window.Respect retry-after headers and back off.
503Service UnavailableProcessing capacity temporarily unavailable.Retry after a short delay.

Error responses follow this format:

{
  "detail": "You do not have enough credit for this job."
}

Best Practices

Recommendations for building a reliable integration.

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.

Store cancel tokens

Save the cancel_token from job responses if you need to implement user-facing cancellation without re-authentication.

Use browser uploads for large files

Files over 25 MB should use the browser upload flow. This avoids double-proxying through your server and is significantly faster.

Specify language for accuracy

Automatic detection is accurate, but specifying the language code yields better results — especially for code-switching or accented speech.

Download results promptly

Transcript JSON downloads are available for up to 7 days after job completion. Download and archive results you need to keep.

Handle rate limits gracefully

Check for 429 responses and implement retry logic with exponential backoff. Use the Retry-After header to determine wait time.