Quickstart
Get an API key, set one environment variable, and turn a local audio file into word-level timestamps — with the AssemblyAI SDK, the native SDK, or curl.
By the end of this page you will have a Sandchest API key in your environment and a completed transcript printed as words with millisecond timings. Pick one of the three paths in step 3; they all produce the same transcript.
1. Get an API key#
- Open sandchest.com/dashboard and sign in. Sign-in is a six-digit code sent to your email — there is no password.
- Go to API keys and create a key. Give it a name you will recognise later
(
local dev,staging worker). - Copy it now. Keys start with
sc_live_and are shown exactly once; Sandchest stores only a hash, so a lost key must be replaced rather than recovered.
2. Put the key in your environment#
export SANDCHEST_API_KEY="sc_live_..."For a project, put it in .env.local (or .env) and make sure that file is
git-ignored:
SANDCHEST_API_KEY=sc_live_...Check it is set:
echo "${SANDCHEST_API_KEY:0:8}"sc_live_3. Transcribe a file#
You need a local audio or video file. Anything FFmpeg can decode works —
.mp3, .m4a, .wav, .mp4, .webm. The examples below use meeting.mp3.
With the AssemblyAI SDK#
If your project already uses assemblyai, keep it. Change the key and the base URL.
npm install assemblyai # or: bun add assemblyaiimport { readFile } from "node:fs/promises";
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: await readFile("meeting.mp3"),
});
if (transcript.status === "error") {
throw new Error(transcript.error ?? "Transcription failed.");
}
console.log(transcript.text);
for (const word of transcript.words ?? []) {
console.log(`${word.start}\t${word.end}\t${word.text}`);
}transcribe() uploads the bytes, creates the transcript, and polls until it is
finished. The AssemblyAI SDK owns the polling loop — Sandchest's GET returns the
current state immediately rather than holding the connection open.
With @sandchest/sdk#
bun add @sandchest/sdk # or: npm install @sandchest/sdkimport { readFile } from "node:fs/promises";
import { Sandchest } from "@sandchest/sdk";
const client = new Sandchest({ apiKey: process.env.SANDCHEST_API_KEY as string });
const transcript = await client.transcripts.transcribe({
audio: await readFile("meeting.mp3"),
});
if (transcript.status === "error") {
throw new Error(transcript.error ?? "Transcription failed.");
}
console.log(transcript.text);
for (const word of transcript.words ?? []) {
console.log(`${word.start}\t${word.end}\t${word.text}`);
}The base URL defaults to https://stt-api.sandchest.com; pass baseUrl only when you
are pointing at your own deployment.
With curl#
Three calls: upload the bytes, create the transcript, poll until it settles.
API="https://stt-api.sandchest.com"
# 1. Upload raw bytes. This is not a multipart form.
UPLOAD_URL=$(curl -sS "$API/v2/upload" \
-H "Authorization: $SANDCHEST_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @meeting.mp3 | jq -r .upload_url)
# 2. Create the transcript.
ID=$(curl -sS "$API/v2/transcript" \
-H "Authorization: $SANDCHEST_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"audio_url\":\"$UPLOAD_URL\"}" | jq -r .id)
# 3. Poll. GET returns the current state immediately, so you drive the loop.
while true; do
STATUS=$(curl -sS "$API/v2/transcript/$ID" \
-H "Authorization: $SANDCHEST_API_KEY" | jq -r .status)
echo "$STATUS"
[ "$STATUS" = completed ] || [ "$STATUS" = error ] && break
sleep 2
done4. Read the words#
Every word carries start and end in milliseconds and a confidence between
0 and 1.
curl -sS "$API/v2/transcript/$ID" \
-H "Authorization: $SANDCHEST_API_KEY" \
| jq -r '.words[] | "\(.start)\t\(.end)\t\(.text)"' | head0 280 Okay
300 520 so,
980 1090 the
1100 1480 deploy
1500 1690 wentThe full transcript object also carries text, confidence, audio_duration (in
seconds), language_code, language_confidence and speech_model_used. See
Transcript options for every field.
Verify#
Run this. It should print completed and a non-empty transcript id.
curl -sS "https://stt-api.sandchest.com/v2/transcript/$ID" \
-H "Authorization: $SANDCHEST_API_KEY" \
| jq '{id, status, language_code, audio_duration, speech_model_used, words: (.words | length)}'{
"id": "tr_...",
"status": "completed",
"language_code": "en",
"audio_duration": 4.8,
"speech_model_used": "nvidia/parakeet-tdt-0.6b-v2",
"words": 14
}If status is error, read the error field — it says exactly what went wrong.
Errors and limits maps every failure to what to do about it.
Next#
Set up with an AI agent — hand these docs to a coding agent and let it wire Sandchest in for you.