NomonoPlatform docs

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"}    ]  }'
201 Created
{  "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:

ProductValueWhat it does
enhancement{"preset": "listening.full"}, requiredChooses the enhancement preset, one of four.
separation{"keep_bleed": 0.1, "keep_background": 0.2}, optionalSets how much of the other voices and of the background is kept.
analysistrue or false, optional, false by defaultMeasures each processed track.
spatialization{"positions": "measured"}, optionalPlaces 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:

PresetDescription
listening.fullFull enhancement for listening
listening.mediumMedium enhancement for listening
listening.lightLight enhancement for listening
spatial.minimalSpatial 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:

ModeDescription
measuredSpeaker positions measured from the bed as they move
staticSpeaker positions measured from the bed and held fixed
stageSpeakers 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:

TypeOptionsWhat comes back
tracksformat: wavOne processed track per microphone, or the processed mixdown.
mixformat: stereo or binauralA mix of the voices.
admprofile: ebu or dolby, and optionally bed_config: bformat, 7.1.2, 5.1 or 2.0An 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:

400 Bad Request
{  "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:

MessageHint
Separation needs keep_bleed, keep_background or both—
A dolby ADM output cannot have bed_config bformatUse bed_config 7.1.2, 5.1 or 2.0
Two ADM outputs ask for the {profile} profileAsk for each profile once
An ADM output cannot be made in the same job as tracks, a mix or an analysisCreate 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 outputAdd a tracks output; the analysis describes the processed tracks
There is nothing to writeAsk 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.spatializationCreate 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.spatializationAdd products.spatialization with a binaural mix or an ADM output, or use a listening preset
Separation cannot be used with the spatial.minimal presetUse 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".

400 Bad Request
{  "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.

A binaural mix and the tracks
{  "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e",  "products": {    "enhancement": {"preset": "listening.full"},    "spatialization": {"positions": "measured"}  },  "outputs": [    {"type": "tracks", "format": "wav"},    {"type": "mix", "format": "binaural"}  ]}
EBU and Dolby ADM files
{  "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:

StatusWhat it means
queuedThe job is waiting to start, or processing has started and the status hasn't changed yet.
processingThe job is being processed.
assemblingThe ADM files are being written. Only ADM jobs have this status.
doneThe outputs are ready.
failedThe job failed, and error says how.
cancelledYou 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"
200 OK
{  "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:

MessageWhen
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.
200 OK
{  "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 codeMessageHint
409 job_not_cancellableThe job is {status}; only a queued job can be cancelled—
409 job_not_cancellableThe job has already been handed over for processing and cannot be cancelledWait for it to finish
409 Conflict
{  "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"  }}