On this page
You need
- An API key from the console's API keys page. Signing up grants $20 of credit.
- A recording of two people talking over each other, as
conversation.wavin the current directory, and eithercurlwithjq, Python withrequests, or Node 18+.
The five calls
GET /v1/creditsreads the balance. It costs nothing and proves the key before you send a file.POST /v1/uploadsdeclares the recording, thenPUT /v1/uploads/{id}/contentsends its bytes as a raw body. The upload turnsreadywith the duration we measured. Uploads are never charged.POST /v1/jobs/separationnames that upload id. The job is quoted, held against your credit, and queued.GET /v1/jobs/{id}reportsstatusgoingqueued→running→succeeded, withstagenaming the step it is on.GET /v1/jobs/{id}/stems/{name}downloads each name inresult.stems[]: one clean track per speaker, with thesi_sdrit scored.
Every job type costs $0.50 per minute of audio, prorated by the second with no minimum charge, and only a job that succeeds is charged. One file per microphone instead? Same body, same flow: 2 to 10 upload ids to /v1/jobs/dominant-separation, with an optional stages object where this one takes pipeline (Run a separation).
The program
All five, in one file. Paste your key into the first line and run it; it ends with the separated tracks in the current directory. Streaming and callbacks instead of polling are in Track a job; FLAC and ZIP downloads in Get results.
set -euo pipefail
export DUETA_API_KEY="mk_live_..."
BASE="https://dueta.ai"
AUTH="Authorization: Bearer $DUETA_API_KEY"
# 1. The key works.
curl -sS -H "$AUTH" "$BASE/v1/credits" | jq .balance_usd
# 2. Declare the recording, then send its bytes.
UPLOAD_ID=$(curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d "{\"filename\": \"conversation.wav\", \"size_bytes\": $(wc -c < conversation.wav)}" \
"$BASE/v1/uploads" | jq -r .id)
curl -sS -X PUT -H "$AUTH" -H "Content-Type: application/octet-stream" \
--data-binary @conversation.wav "$BASE/v1/uploads/$UPLOAD_ID/content" | jq '{state, duration_seconds}'
# 3. Create the job.
JOB_ID=$(curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d "{\"inputs\": [\"$UPLOAD_ID\"]}" "$BASE/v1/jobs/separation" | jq -r .id)
# 4. Poll until it is done.
while :; do
JOB=$(curl -sS -H "$AUTH" "$BASE/v1/jobs/$JOB_ID")
case "$(echo "$JOB" | jq -r .status)" in
succeeded) break ;;
queued|running) sleep 5 ;;
failed|canceled) echo "$JOB" | jq -r .error; exit 1 ;;
*) echo "$JOB"; exit 1 ;; # not a job at all: an error body
esac
done
# 5. One clean track per speaker.
for NAME in $(echo "$JOB" | jq -r '.result.stems[].name'); do
curl -sS -H "$AUTH" -o "$NAME.wav" "$BASE/v1/jobs/$JOB_ID/stems/$NAME"
done