Tuplets Python SDK
Official Python client for the Tuplets API — transcribe audio, run speaker diarization, apply PII redaction, and request structured analytics from Python 3.10+.
- Docs: tuplets.ai/docs
- API reference: api.tuplets.ai
- Get an API key: tuplets.ai/settings/api-keys
Installation
pip install tuplets-ai
Requires Python 3.10+. The only runtime dependency is httpx.
Quick start
Transcribe a local file, wait for completion, and print the transcript:
import os
from tuplets_ai import JobCreateParams, TupletsClient
client = TupletsClient(api_key=os.environ["TUPLETS_API_KEY"])
job = client.jobs.create_from_file(
"interview.mp3",
params=JobCreateParams(language="en"),
)
final_job = client.jobs.wait(job.id)
if final_job.status == "completed":
transcript = client.jobs.download_result(job.id)
print(transcript["text"])
elif final_job.status == "failed":
print(final_job.error_message)
Authentication
Create an API key in the Tuplets dashboard (prefix tb_) and pass it when constructing the client:
client = TupletsClient(api_key="tb_your_api_key")
Every authenticated request sends Authorization: Bearer tb_....
Client configuration
import httpx
from tuplets_ai import TupletsClient
# Custom base URL (defaults to https://api.tuplets.ai)
client = TupletsClient(
api_key="tb_your_api_key",
base_url="https://api.tuplets.ai",
timeout=120.0,
)
# Reuse your own httpx client (connection pooling, proxies, retries, etc.)
http = httpx.Client(base_url="https://api.tuplets.ai", timeout=120.0)
client = TupletsClient(api_key="tb_your_api_key", http_client=http)
with client:
...
# or explicitly:
client.close()
Use AsyncTupletsClient the same way with httpx.AsyncClient and async with.
Submitting transcription jobs
All job submission methods return a JobAccepted object with id, status_url, cancel_url, and cancel_token.
From a local file
job = client.jobs.create_from_file(
"call.wav",
params=JobCreateParams(language="en", transcription_model="premium"),
)
From bytes (in memory)
from pathlib import Path
audio = Path("call.wav").read_bytes()
job = client.jobs.create_from_bytes(
filename="call.wav",
data=audio,
params=JobCreateParams(language="auto"),
)
From a remote URL
Tuplets fetches the audio from a publicly reachable URL:
job = client.jobs.create_from_url(
"https://storage.example.com/recordings/call.mp3",
params=JobCreateParams(language="en"),
)
From a direct upload
For large files, upload to object storage first, then reference the upload when creating the job (see Direct uploads).
job = client.jobs.create_from_uploaded_audio(
object_key=upload.object_key,
upload_token=upload.upload_token,
params=JobCreateParams(language="en"),
)
Job parameters
Pass options via JobCreateParams:
| Parameter | Type | Default | Description |
|---|---|---|---|
language |
str |
"auto" |
BCP-47 language code or "auto" for detection |
transcription_model |
"standard" | "premium" |
"standard" |
Accuracy/latency tier |
diarization |
bool |
False |
Speaker attribution; when enabled, jobs fail if diarization cannot be produced |
pii_processing |
bool |
False |
Detect and redact personally identifiable information |
analytics |
dict |
None |
Structured post-transcription analytics (see below) |
params = JobCreateParams(
language="en",
transcription_model="premium",
diarization=True,
pii_processing=True,
)
Polling, waiting, and results
Poll manually
status = client.jobs.get(job.id)
print(status.status) # queued | running | completed | failed
print(status.progress_percent) # 0–100 while running
print(status.estimated_seconds_remaining)
print(status.result) # inline preview when completed
print(status.error_message) # set when status == "failed"
Wait until finished
wait() polls until the job reaches completed or failed:
final_job = client.jobs.wait(
job.id,
poll_interval=2.0, # seconds between polls (default: 2)
timeout=600.0, # optional; raises WaitTimeoutError
)
Download the full transcript
transcript = client.jobs.download_result(job.id)
print(transcript["text"])
for segment in transcript.get("segments", []):
print(segment["start"], segment["end"], segment["text"])
When diarization=True, segments include speaker labels. Completed jobs may also include an analytics object if analytics were requested.
Downloaded JSON includes feature_execution.transcription_model_requested and feature_execution.transcription_model_applied so archived result files record whether standard or premium transcription ran.
List and cancel jobs
recent = client.jobs.list(status="completed", limit=20)
for item in recent.items:
print(item.id, item.status, item.created_at)
client.jobs.cancel(job.id)
# Cancel without storing the job id (uses token from JobAccepted)
client.jobs.cancel_with_token(job.cancel_token)
Direct uploads
Upload large audio files to signed storage, then create a job from the upload reference:
from pathlib import Path
from tuplets_ai import JobCreateParams, TupletsClient
client = TupletsClient(api_key="tb_your_api_key")
file_path = Path("large-audio.wav")
upload = client.uploads.create_target(
filename=file_path.name,
size=file_path.stat().st_size,
content_type="audio/wav",
)
client.uploads.upload_file(upload, file_path)
job = client.jobs.create_from_uploaded_audio(
object_key=upload.object_key,
upload_token=upload.upload_token,
params=JobCreateParams(language="en", transcription_model="premium"),
)
create_target returns a BrowserUploadTarget with a pre-signed upload_url, required upload_headers, and an expiry (expires_in_seconds). Upload with upload_file / upload_bytes, or PUT the bytes yourself using the signed URL.
Analytics
Request generic and custom schema-bound analytics with JobCreateParams.analytics:
job = client.jobs.create_from_file(
"insurance-call.mp3",
params=JobCreateParams(
language="en",
analytics={
"profile": "full",
"domain": "insurance",
"schema": {
"fields": [
{
"key": "call_reason",
"label": "Reason for call",
"type": "single_select",
"options": [
{"id": 1, "code": "CLAIM_STATUS", "label": "Claim status"},
{"id": 2, "code": "BILLING", "label": "Billing question"},
],
}
]
},
},
),
)
final_job = client.jobs.wait(job.id)
if final_job.analytics:
print(final_job.analytics["custom"]["fields"])
See tuplets.ai/docs for supported profiles, domains, and schema field types.
Async usage
The async client mirrors the sync API:
from tuplets_ai import AsyncTupletsClient, JobCreateParams
async def main() -> None:
async with AsyncTupletsClient(api_key="tb_your_api_key") as client:
job = await client.jobs.create_from_url(
"https://storage.example.com/call.mp3",
params=JobCreateParams(language="en", pii_processing=True),
)
final_job = await client.jobs.wait(job.id)
if final_job.status == "completed":
transcript = await client.jobs.download_result(job.id)
print(transcript["text"])
elif final_job.status == "failed":
print(final_job.error_message)
Error handling
API failures raise typed exceptions with status_code and optional response_body:
| Exception | HTTP status |
|---|---|
ValidationError |
400 |
AuthenticationError |
401 |
PaymentRequiredError |
402 |
PermissionDeniedError |
403 |
NotFoundError |
404 |
ConflictError |
409 |
GoneError |
410 |
RateLimitError |
429 |
APIStatusError |
other 4xx/5xx |
WaitTimeoutError |
polling timeout (not an HTTP error) |
from tuplets_ai import AuthenticationError, RateLimitError, TupletsClient
client = TupletsClient(api_key="tb_your_api_key")
try:
client.jobs.get("job_unknown")
except AuthenticationError as exc:
print(exc.status_code, exc.message)
except RateLimitError:
...
API surface
| Resource | Methods |
|---|---|
client.jobs |
create_from_file, create_from_bytes, create_from_url, create_from_uploaded_audio, get, list, wait, cancel, cancel_with_token, download_result |
client.uploads |
create_target, upload_file, upload_bytes |
client.solutions |
create_inquiry (public enterprise inquiries; no API key required) |
Exported types
JobCreateParams, JobAccepted, JobStatus, JobList, BrowserUploadTarget, UploadedAudioReference, SolutionsInquiryRequest, SolutionsInquirySubmission, and the exception classes above are exported from the top-level tuplets_ai package.
Support
- Documentation: tuplets.ai/docs
- Contact: contact@tuplets.ai
Release files for tuplets-ai 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tuplets_ai-0.3.2.tar.gz | 10.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tuplets_ai-0.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:24.0 kB
Release files / tuplets_ai-0.3.2.tar.gz
| Download URL | tuplets_ai-0.3.2.tar.gz |
|---|---|
| Size | 10.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6a01efb18d910010bb0946b674a4b00d26a0d19007ee30f9fd6e7947ae29a321
|
|
BLAKE2b-256 checksum How to use checksums |
7d05d8eefec8417ecc9db36d51adf1b8193413e062c78dcdc4b8441f52c23bce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / tuplets_ai-0.3.2-py3-none-any.whl
| Download URL | tuplets_ai-0.3.2-py3-none-any.whl |
|---|---|
| Size | 13.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0448c1a8944ccc672c56e5cbbed7611339953040d6fffd030e23d9c5ec2a8640
|
|
BLAKE2b-256 checksum How to use checksums |
315aca3c92657a5d2dec5fb878b4334555093b813802af7d79fd8c9d02d9d176
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|