Skip to content
DUETA
Docs

Run a separation

Price a job, then create it from upload ids: Duplex for one mixed file, Dominant for one file per microphone.

On this page
You need
  • One or more uploads in state ready. See Upload audio.
  • Credit for the longest input at $0.50 a minute. The quote below tells you before you commit.

Get a quote

POST/v1/jobs/quote

The same arithmetic the submission does, on the same server-measured durations. Nothing is reserved. reasons[] carries every refusal the submission would raise, as sentences, so a half-ready set still gets a price and an explanation.

FieldTypeMeaning
typestringseparation or dominant_separation.
inputsstring[]Upload ids, in order.
json
{
  "type": "separation",
  "inputs": ["upl_9f2c7a41d0e8"],
  "billable_seconds": 612.4,
  "total_duration_seconds": 612.4,
  "estimated_cost_usd": 5.1,
  "balance_usd": 20.0,
  "sufficient_credit": true,
  "can_submit": true,
  "reasons": []
}

// Not submittable yet: every refusal comes back as a sentence, not an error.
{ "sufficient_credit": false, "can_submit": false,
  "reasons": ["These uploads have not finished: upl_4a81be03c5f7",
              "This job costs more than your balance. Add credit in the console."] }
bash
curl -X POST https://dueta.ai/v1/jobs/quote \
  -H "Authorization: Bearer $DUETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "separation", "inputs": ["upl_9f2c7a41d0e8"]}'

Run Duplex separation

POST/v1/jobs/separation

One recording in which two people talk over each other; two clean speaker tracks out. The whole chain runs inside this one job. Every step is on by default; switch one off in pipeline. Answers 201 with the job.

FieldTypeMeaning
inputsstring[1]Exactly one upload id.
pipelineobjectOptional. Step name to true or false; a missing key keeps its default.
callback_urlstringOptional. See Receive callbacks.
pipeline keyDefaultTurn it off when
vocal_separationtrueStrips music and background before separating. Turn it off when the recording is already dry speech: a studio double-ender, a headset call, a meeting-room capture with nothing playing.
enhancementtrueDenoises each separated speaker track. Turn it off on already-clean studio material, where denoising can only risk softening a voice that had nothing wrong with it.
super_resolutiontrueWrites 48 kHz output instead of 16 kHz. Turn it off when your pipeline consumes 16 kHz and would only resample the extra bandwidth away, as most ASR, telephony and VoIP paths do.
scoringtrueEstimates SI-SDR and reports it per track. Turn it off when you never read the number, such as an automated pipeline that keeps whatever comes back.

A job configured for super_resolution writes 48 kHz output; a job configured without it writes 16 kHz. Multipart submission with files=@conversation.wav and one form field per toggle still works; it creates the upload for you.

bash
curl -X POST https://dueta.ai/v1/jobs/separation \
  -H "Authorization: Bearer $DUETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"inputs": ["upl_9f2c7a41d0e8"],
       "pipeline": {"super_resolution": false}}'
# -> 201, the job. Omit "pipeline" to run every step.

Run Dominant separation

POST/v1/jobs/dominant-separation

One close-mic recording per speaker, 2 to 10 of them, made in the same room at the same time. Each comes back holding only its own speaker, plus one ambience track for the room. There is no pipeline on this product. Order matters: the first upload is the timeline the rest are aligned against.

FieldTypeMeaning
inputsstring[2..10]Upload ids, one per microphone, in alignment order.
callback_urlstringOptional.
bash
# 2-10 upload ids, one per microphone. The FIRST is the timeline the
# others are aligned against.
curl -X POST https://dueta.ai/v1/jobs/dominant-separation \
  -H "Authorization: Bearer $DUETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"inputs": ["upl_9f2c7a41d0e8", "upl_4a81be03c5f7"]}'

Read the job back

GET/v1/jobs/{id}

The creation response and every later read are the same shape. The price is frozen at creation: estimated_cost_usd is what you will be billed on success, whatever the worker reports.

json
{
  "id": "0f9c1a7e-4b21-4d5a-9d0e-2c8b6a1f3e77",
  "type": "separation",
  "status": "queued",
  "stage": "queued",
  "progress": 0,
  "eta_seconds": null,
  "queue_position": 2,
  "worker_alive": true,
  "heartbeat_age_seconds": 3.2,
  "pipeline": { "vocal_separation": true, "enhancement": true,
                "super_resolution": false, "scoring": true },
  "inputs": [
    { "index": 0, "upload_id": "upl_9f2c7a41d0e8", "filename": "conversation.wav",
      "duration_seconds": 612.4, "stem": "conversation-00", "sample_rate": 48000,
      "channels": 2, "state": "ready", "checksum_sha256": "b1946ac9..." }
  ],
  "steps": [
    { "name": "vocal_separation", "state": "pending", "progress": 0 },
    { "name": "separation",       "state": "pending", "progress": 0 },
    { "name": "enhancement",      "state": "pending", "progress": 0 },
    { "name": "super_resolution", "state": "skipped", "progress": 0 },
    { "name": "si_sdr",           "state": "pending", "progress": 0 }
  ],
  "estimated_cost_seconds": 612.4,
  "estimated_cost_usd": 5.1,
  "billed_seconds": null,
  "billed_usd": null,
  "callback_secret": null,
  "error": null,
  "result": null,
  "created_at": "2026-08-28T09:21:44Z",
  "started_at": null,
  "finished_at": null
}
FieldTypeMeaning
idstringThe job id used by every later route.
statusstringqueued at creation. Lifecycle in Track a job.
inputs[]object[]One record per recording, naming its upload_id and reading its measurements through.
pipelineobjectThe toggles this job runs, all four keys. Empty on a Dominant job.
estimated_cost_secondsfloatThe longest input's duration: what the job is billed on.
estimated_cost_usdfloatHeld now, charged on success, released on failure or cancel.
callback_secretstringOnly on the creation response, and only when a callback_url was sent.
bash
curl -H "Authorization: Bearer $DUETA_API_KEY" https://dueta.ai/v1/jobs/$JOB_ID |
  jq '{status, stage, progress, queue_position, estimated_cost_usd, pipeline}'

Cases

402
Insufficient credit. No job exists and nothing was charged; the uploads are untouched. Top up and submit the same ids.
404
An id in inputs is not one of your uploads.
409
An input is not ready, or your email is unverified where verification is required.
400 count
separation takes exactly 1 file; dominant-separation takes 2 to 10.
400 duration
All inputs added together exceed the 2-hour cap. The quote reports the same sentence in reasons[] first.
400 take
Dominant inputs must be one take: the longest may be at most 2× the shortest.
400 body
Send inputs; pipeline must map step names to booleans.
415
A multipart part is video.
429
5 jobs already queued or running, 20 submissions in the last minute, or 20 unbilled (failed or canceled) jobs in the last hour. Retry-After says when to ask again.
503
The job queue could not be reached. Retry with backoff; nothing was held.
Billing
Billed on the longest input, never the sum. Billed equals quoted. A failed or canceled job is never charged. Accounts that have bought credit queue ahead of free ones.