Using the AssemblyAI SDK
Change apiKey and baseUrl and your existing AssemblyAI code runs on Sandchest. Here is exactly which endpoints and options are supported, and which are rejected.
Sandchest speaks the AssemblyAI prerecorded API at /v2/*. If you already have
AssemblyAI code, keep the official SDK and change two settings. This page shows the
swap in TypeScript and Python, then lists precisely what works, what is refused, and
where the behaviour differs.
The swap#
TypeScript#
import { AssemblyAI } from "assemblyai";
const client = new AssemblyAI({
apiKey: process.env.SANDCHEST_API_KEY as string,
baseUrl: "https://stt-api.sandchest.com",
});
const transcript = await client.transcripts.transcribe({
audio: audioBuffer,
disfluencies: true,
});
console.log(transcript.speech_model_used);
console.log(transcript.words);Python#
import os
import assemblyai as aai
aai.settings.api_key = os.environ["SANDCHEST_API_KEY"]
aai.settings.base_url = "https://stt-api.sandchest.com"
transcript = aai.Transcriber().transcribe("meeting.mp3")
print(transcript.text)
for word in transcript.words:
print(word.start, word.end, word.text)That is the whole migration. Uploads, transcript creation, polling, listing, deletion, word search, sentences, paragraphs, SRT and VTT all go through unchanged.
Supported endpoints#
| Method | Path | Notes |
|---|---|---|
POST | /v2/upload | Raw bytes in the body |
POST | /v2/transcript | Idempotency-Key accepted |
GET | /v2/transcript/:id | Returns the current state immediately |
GET | /v2/transcript | limit, status, created_on, before_id, after_id |
DELETE | /v2/transcript/:id | Erases words, text and source URLs |
GET | /v2/transcript/:id/sentences | Completed transcripts only |
GET | /v2/transcript/:id/paragraphs | Completed transcripts only |
GET | /v2/transcript/:id/word-search | words= required |
GET | /v2/transcript/:id/srt | chars_per_caption supported |
GET | /v2/transcript/:id/vtt | chars_per_caption supported |
Those ten paths are the complete surface. Streaming/real-time transcription, LeMUR, and the AssemblyAI audio-intelligence endpoints are not implemented. Full details in the API reference.
Supported options#
audio_url, speech_model, speech_models, language_code, language_detection,
language_confidence_threshold, language_detection_options, punctuate,
format_text, disfluencies, custom_spelling, multichannel, audio_start_from,
audio_end_at, webhook_url, webhook_auth_header_name and
webhook_auth_header_value.
Every field is documented in Transcript options.
Options that are rejected#
Sandchest never acknowledges a request whose options it silently dropped. If it cannot do the thing you asked for, it says so with HTTP 400 and this exact body shape:
| You sent | Response |
|---|---|
speaker_labels: true or any speakers_expected | {"error":"Speaker identification is not supported."} |
a non-empty word_boost, or any boost_param | {"error":"Custom word boosting is not supported."} |
| any option Sandchest does not implement | {"error":"The request contains an unsupported option or an invalid option value."} |
That last row is the one to plan for. The AssemblyAI audio-intelligence options —
summarization, auto_chapters, auto_highlights, entity_detection,
content_safety, iab_categories, sentiment_analysis, redact_pii,
dual_channel, language_codes and friends — are not in Sandchest's schema, so a
request carrying them is refused rather than quietly stripped. Remove them before
you switch a workload over.
The language options have their own rules:
| You sent | Response |
|---|---|
no language_code and language_detection: false | {"error":"Either `language_detection` must be set to True, or one of `language_code` or `language_codes` must must be specified."} |
a language_code and language_detection: true | {"error":"`language_detection` is not available when `language_code` is specified."} |
language_confidence_threshold without detection | {"error":"language_confidence_threshold requires language_detection."} |
Omit both and you get automatic detection, which is what most callers want. See Languages.
Differences to expect#
GET returns immediately. AssemblyAI's GET /v2/transcript/:id and Sandchest's
both return the current state without waiting. The SDK's transcribe() and
waitUntilReady() own the polling loop, at their configured interval. Nothing to
change — just do not write code that assumes the request blocks until completion.
speech_model_used tells the truth. You can keep sending AssemblyAI model names
in speech_models or speech_model for compatibility; they are accepted and echoed
back in the response's speech_models. speech_model_used reports the model that
genuinely produced the transcript, for example nvidia/parakeet-tdt-0.6b-v2.
disfluencies defaults to false. New transcripts drop English filled pauses
("um", "uh") unless you ask for them. Send disfluencies: true for verbatim output.
Deletion is a tombstone. DELETE erases words, text, source URLs, custom
vocabulary and private error detail, then returns an object with
status: "completed", text: "Deleted by user." and audio_url: "http://deleted_by_user". Usage and billing history survive.
Unknown transcript ids are a 400, not a 404. The compatibility endpoints match
AssemblyAI here: {"error":"Transcript lookup error, transcript id not found"} with
HTTP 400. The native endpoint at /api/v1/transcripts/:id returns a plain 404
instead.
Non-English coverage is narrower than the code list. The API accepts the full
AssemblyAI language-code list, but the deployed model decodes a smaller set. A code
outside it fails at inference time with a clear message on the transcript's error
field. Languages has the exact list.
Verify#
Run your existing AssemblyAI code against Sandchest and check the model identifier — if it names a Parakeet model, you are on Sandchest and not on AssemblyAI.
curl -sS "https://stt-api.sandchest.com/v2/transcript/$ID" \
-H "Authorization: $SANDCHEST_API_KEY" \
| jq '{status, speech_model_used, speech_models}'{
"status": "completed",
"speech_model_used": "nvidia/parakeet-tdt-0.6b-v2",
"speech_models": ["universal-2"]
}Next#
Transcript options — every request field and every field on the object that comes back.