Skip to content
DUETA
Docs

Quickstart

Key in hand to separated tracks: five calls, one program to copy.

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.wav in the current directory, and either curl with jq, Python with requests, or Node 18+.

The five calls

  1. GET /v1/credits reads the balance. It costs nothing and proves the key before you send a file.
  2. POST /v1/uploads declares the recording, then PUT /v1/uploads/{id}/content sends its bytes as a raw body. The upload turns ready with the duration we measured. Uploads are never charged.
  3. POST /v1/jobs/separation names that upload id. The job is quoted, held against your credit, and queued.
  4. GET /v1/jobs/{id} reports status going queuedrunningsucceeded, with stage naming the step it is on.
  5. GET /v1/jobs/{id}/stems/{name} downloads each name in result.stems[]: one clean track per speaker, with the si_sdr it 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.

bash
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