Concepts
Jobs
A job runs on a session, and its products and outputs decide what is done to the audio and which files you get back.
Creating a job
POST /v1/jobs takes the session_id, the products and the outputs. Any field we don't know returns 400 validation_error. This job asks for the processed tracks, a stereo mix and an analysis:
curl -X POST "https://platform-api.nomono.co/v1/jobs" \ -H "Authorization: Bearer $NOMONO_API_KEY" \ -H "Idempotency-Key: episode-12-enhance" \ -H "Content-Type: application/json" \ -d '{ "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e", "products": { "enhancement": {"preset": "listening.full"}, "separation": {"keep_bleed": 0.1, "keep_background": 0.2}, "analysis": true }, "outputs": [ {"type": "tracks", "format": "wav"}, {"type": "mix", "format": "stereo"}, {"type": "analysis"} ] }'{ "job_id": "job_01a14471b2d47f19b6a3c0e5d8f9a1b2", "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e", "status": "queued", "progress": 0.0, "products": { "enhancement": {"preset": "listening.full"}, "separation": {"keep_bleed": 0.1, "keep_background": 0.2}, "analysis": true }, "outputs_requested": [ {"type": "tracks", "format": "wav"}, {"type": "mix", "format": "stereo"}, {"type": "analysis"} ], "minutes": 30.57, "created_at": "2026-10-16T09:13:02.071624Z", "started_at": null, "finished_at": null, "error": null, "retry_of": null}The job starts out queued. If you sent an Idempotency-Key, a retry with the same key and body within 24 hours returns this job instead of a new one.
Products
The products say what is done to the audio:
| Product | Value | What it does |
|---|---|---|
enhancement | {"preset": "listening.full"}, required | Chooses the enhancement preset, one of four. |
separation | {"keep_bleed": 0.1, "keep_background": 0.2}, optional | Sets how much of the other voices and of the background is kept. |
analysis | true or false, optional, false by default | Measures each processed track. |
spatialization | {"positions": "measured"}, optional | Places the speakers for a binaural mix or ADM files, and needs a session with a bed. |
Enhancement presets
Set products.enhancement.preset to one of:
| Preset | Description |
|---|---|
listening.full | Full enhancement for listening |
listening.medium | Medium enhancement for listening |
listening.light | Light enhancement for listening |
spatial.minimal | Spatial processing only, with nothing enhanced apart from the level |
spatial.minimal places the microphones in the binaural mix or ADM files and enhances nothing apart from their level. It needs spatialization and can't be combined with separation.
Any other value returns 400 validation_error. You can also read the presets and the position modes from GET /v1/presets.
Separation
keep_bleed sets how much of the other voices picked up by each microphone is kept, and keep_background how much of the background noise. Each takes a value from 0 to 1. Set at least one of them, and the one you leave out keeps the preset's value. The values are linear gains, so 0.1 is −20 dB, 0.5 is about −6 dB and 0 gives the floor of −60 dB.
Analysis
Setting "analysis": true gives you an analysis of each processed track's loudness, peak and problems. It needs both an analysis output and a tracks output.
Spatialization
spatialization.positions sets how the speakers are placed:
| Mode | Description |
|---|---|
measured | Speaker positions measured from the bed as they move |
static | Speaker positions measured from the bed and held fixed |
stage | Speakers arranged in an arc |
Every mode needs a session with a bed, stage included, and ADM outputs need measured. For now a binaural mix is rendered with stage whatever mode you set, as Binaural mixes explains.
Outputs
outputs lists the files you want back, and each entry has a type:
| Type | Options | What comes back |
|---|---|---|
tracks | format: wav | One processed track per microphone, or the processed mixdown. |
mix | format: stereo or binaural | A mix of the voices. |
adm | profile: ebu or dolby, and optionally bed_config: bformat, 7.1.2, 5.1 or 2.0 | An ADM file for the profile. |
analysis | — | The analysis of the tracks. |
Each track and mix also comes with an Opus copy and waveform data.
An invalid field returns 400 validation_error with its path in details.fields:
{ "error": { "code": "validation_error", "message": "The request is not valid", "details": { "fields": [ {"field": "body.outputs.0.mix.format", "message": "Input should be 'stereo' or 'binaural'"} ] } }}Combination rules
A job that breaks one of these rules returns 400 validation_error with the rule as its message:
| Message | Hint |
|---|---|
| Separation needs keep_bleed, keep_background or both | — |
| A dolby ADM output cannot have bed_config bformat | Use bed_config 7.1.2, 5.1 or 2.0 |
| Two ADM outputs ask for the {profile} profile | Ask for each profile once |
| An ADM output cannot be made in the same job as tracks, a mix or an analysis | Create a separate job on the same session for the tracks, mix or analysis |
| An analysis output needs products.analysis set to true | — |
| Setting products.analysis to true needs an analysis output | — |
| An analysis output needs a tracks output | Add a tracks output; the analysis describes the processed tracks |
| There is nothing to write | Ask for tracks, a mix or an ADM output |
| A binaural mix needs products.spatialization | — |
| An ADM output needs products.spatialization | — |
| A stereo mix cannot be made in the same job as products.spatialization | Create a separate job for the stereo mix |
| Spatialization needs a binaural mix or an ADM output | — |
| An ADM output needs products.spatialization.positions set to measured | — |
| The spatial.minimal preset needs products.spatialization | Add products.spatialization with a binaural mix or an ADM output, or use a listening preset |
| Separation cannot be used with the spatial.minimal preset | Use a listening preset to keep part of the bleed or background |
The session can also make the request fail. An unknown session_id returns 404 not_found, and asking for spatialization on a session without a bed returns 400 validation_error with "Spatialization needs a session with a bed".
{ "error": { "code": "validation_error", "message": "An ADM output cannot be made in the same job as tracks, a mix or an analysis", "hint": "Create a separate job on the same session for the tracks, mix or analysis" }}ADM outputs need a job of their own, so a binaural mix and ADM files for the same recording take two jobs on the same session, and each one is billed for the session's full length. One ADM job can make both the EBU and the Dolby file.
{ "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e", "products": { "enhancement": {"preset": "listening.full"}, "spatialization": {"positions": "measured"} }, "outputs": [ {"type": "tracks", "format": "wav"}, {"type": "mix", "format": "binaural"} ]}{ "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e", "products": { "enhancement": {"preset": "listening.full"}, "spatialization": {"positions": "measured"} }, "outputs": [ {"type": "adm", "profile": "ebu"}, {"type": "adm", "profile": "dolby", "bed_config": "7.1.2"} ]}Statuses
A job has one of six statuses:
| Status | What it means |
|---|---|
queued | The job is waiting to start, or processing has started and the status hasn't changed yet. |
processing | The job is being processed. |
assembling | The ADM files are being written. Only ADM jobs have this status. |
done | The outputs are ready. |
failed | The job failed, and error says how. |
cancelled | You cancelled the job. |
done and cancelled are final, and so is failed except for a job that timed out. finished_at is set once the job is done, failed or cancelled.
A job can wait in queued while other jobs are processing, because we process a limited number of jobs at a time.
Waiting for a job
Poll GET /v1/jobs/{job_id} every few seconds until the job is done, failed or cancelled, or have a webhook tell you when it finishes. While you wait, progress goes from 0 to 1 and never goes down.
curl "https://platform-api.nomono.co/v1/jobs/job_01a14471b2d47f19b6a3c0e5d8f9a1b2" \ -H "Authorization: Bearer $NOMONO_API_KEY"{ "job_id": "job_01a14471b2d47f19b6a3c0e5d8f9a1b2", "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e", "status": "processing", "progress": 0.42, "products": { "enhancement": {"preset": "listening.full"}, "separation": {"keep_bleed": 0.1, "keep_background": 0.2}, "analysis": true }, "outputs_requested": [ {"type": "tracks", "format": "wav"}, {"type": "mix", "format": "stereo"}, {"type": "analysis"} ], "minutes": 30.57, "created_at": "2026-10-16T09:13:02.071624Z", "started_at": "2026-10-16T09:13:31.402215Z", "finished_at": null, "error": null, "retry_of": null}GET /v1/jobs lists your jobs, newest first and in pages, and you can filter it by session_id or status. Reading jobs needs the outputs:read scope.
Failures
A failed job's error.code is processing_failed, with one of these messages:
| Message | When |
|---|---|
| Processing did not finish within 3 hours. Create the job again; this is safe. Send a new Idempotency-Key if you used one. | Processing made no progress for 3 hours. |
| The job could not be started. Create the job again; this is safe. Send a new Idempotency-Key if you used one. | The job failed before processing started. |
| Processing failed. Create the job again; this is safe. Send a new Idempotency-Key if you used one. | The job failed for any other reason. |
{ "job_id": "job_01a14471b3127a8c9e4d2f6b1a0c3e5d", "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e", "status": "failed", "progress": 0.87, "products": { "enhancement": {"preset": "listening.full"}, "spatialization": {"positions": "measured"} }, "outputs_requested": [ {"type": "tracks", "format": "wav"}, {"type": "mix", "format": "binaural"} ], "minutes": 30.57, "created_at": "2026-10-16T09:13:04.880213Z", "started_at": "2026-10-16T09:13:40.115502Z", "finished_at": "2026-10-16T09:29:12.660418Z", "error": { "code": "processing_failed", "message": "Processing failed. Create the job again; this is safe. Send a new Idempotency-Key if you used one." }, "retry_of": null}A job that times out can still finish within the next 24 hours. If it does, it becomes done, going through assembling first when it has ADM outputs, and it's billed and sends job.completed after its job.failed. While the job can still finish, its session can't be deleted.
When we retry a failed job for you, the new job's retry_of is the ID of the failed one, and otherwise it's null.
Minutes
A job's minutes is its session's duration_s divided by 60 and rounded to two decimals, and jobs are billed by these minutes for each product they use. A job adds its minutes to enhancement, and also to separation, analysis and spatialization when it asks for them.
A job is billed once processing has started, and failed and cancelled jobs aren't billed even though their minutes field still shows the session's length. Every POST /v1/jobs creates a new job unless it repeats an Idempotency-Key, and each job is billed on its own. You can see the totals in GET /v1/usage.
Cancelling a job
DELETE /v1/jobs/{job_id} cancels a queued job and returns 204, without sending a webhook. You can cancel a job only until processing starts, and that can happen while the job still shows queued.
curl -X DELETE "https://platform-api.nomono.co/v1/jobs/job_01a1446c9d837e5fa0b2c4d6e8f1a3b5" \ -H "Authorization: Bearer $NOMONO_API_KEY"A job that can't be cancelled returns one of these errors:
| Status and code | Message | Hint |
|---|---|---|
409 job_not_cancellable | The job is {status}; only a queued job can be cancelled | — |
409 job_not_cancellable | The job has already been handed over for processing and cannot be cancelled | Wait for it to finish |
{ "error": { "code": "job_not_cancellable", "message": "The job has already been handed over for processing and cannot be cancelled", "hint": "Wait for it to finish" }}