Concepts
Sessions
Jobs run on a session, which groups the sources of one recording and gives each of them a role.
Sources and roles
In a session, each source gets a role, an optional label and, for a bed, the array it was recorded with. A source can only belong to one session.
| Role | What it is | Channels | In a session |
|---|---|---|---|
microphone | One person's voice, a mono or stereo file. | 1 or 2 | One to four. |
mixdown | A mono or stereo file with the voices already mixed together. | 1 or 2 | At most one, and alone in its session. |
bed | The A-format recording of an ambisonics array, with array set. | 8 for sound-capsule, 4 for sennheiser-ambeo | At most one, and only with microphones. |
The optional label, up to 200 characters, names the source in the outputs and the analysis, for example "Host".
Creating a session
POST /v1/sessions takes the sources, each with a source_id from a completed upload, and an optional retention_days that sets the session's retention. Any field we don't know returns 400 validation_error. This request creates a session with two microphones and an Ambeo bed:
curl -X POST "https://platform-api.nomono.co/v1/sessions" \ -H "Authorization: Bearer $NOMONO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sources": [ {"source_id": "src_01a1446f235c7448abbe096c9b9adf6c", "role": "microphone", "label": "Host"}, {"source_id": "src_01a1446f8e8f7b23a4c06d1c3e5f7a90", "role": "microphone", "label": "Guest"}, {"source_id": "src_01a144701c287e45b8d39f0a0f1e2d3c", "role": "bed", "array": "sennheiser-ambeo"} ], "retention_days": 30 }'{ "session_id": "ses_01a14471a03b7c56a1e28d9f4b6c7d8e", "status": "ready", "duration_s": 1834.21, "sources": [ { "source_id": "src_01a1446f235c7448abbe096c9b9adf6c", "role": "microphone", "label": "Host", "array": null, "source": { "source_id": "src_01a1446f235c7448abbe096c9b9adf6c", "upload_id": "upl_01a1446f235c7448abbe096bfd043ae3", "filename": "host.wav", "format": "wav", "channels": 1, "sample_rate": 48000, "duration_s": 1834.21, "size_bytes": 176084204, "device": null, "status": "ready", "created_at": "2026-10-16T09:02:11.204518Z", "expires_at": "2026-11-15T09:12:44.518377Z" } }, { "source_id": "src_01a1446f8e8f7b23a4c06d1c3e5f7a90", "role": "microphone", "label": "Guest", "array": null, "source": { "source_id": "src_01a1446f8e8f7b23a4c06d1c3e5f7a90", "upload_id": "upl_01a1446f8e917b23a4c06d1e5f7a8b92", "filename": "guest.wav", "format": "wav", "channels": 1, "sample_rate": 48000, "duration_s": 1834.21, "size_bytes": 176084204, "device": null, "status": "ready", "created_at": "2026-10-16T09:03:02.611730Z", "expires_at": "2026-11-15T09:12:44.518377Z" } }, { "source_id": "src_01a144701c287e45b8d39f0a0f1e2d3c", "role": "bed", "label": null, "array": "sennheiser-ambeo", "source": { "source_id": "src_01a144701c287e45b8d39f0a0f1e2d3c", "upload_id": "upl_01a144701c2a7e45b8d39f0a1b2c3d4e", "filename": "ambeo.wav", "format": "wav", "channels": 4, "sample_rate": 48000, "duration_s": 1834.21, "size_bytes": 1056505004, "device": null, "status": "ready", "created_at": "2026-10-16T09:03:38.402115Z", "expires_at": "2026-11-15T09:12:44.518377Z" } } ], "alignment": "sample_locked", "retention_days": 30, "created_at": "2026-10-16T09:12:44.518377Z", "expires_at": "2026-11-15T09:12:44.518377Z"}The session keeps its sources in the order you sent them, and the outputs and the analysis follow the same order.
Session rules
If a session breaks one of these rules, the request returns 422 session_invalid with the rule as its message, and when the rule is about a particular source, details.source_id names it.
{ "error": { "code": "session_invalid", "message": "A sound-capsule bed has 8 channels; this source has 4", "details": { "source_id": "src_01a144701c287e45b8d39f0a0f1e2d3c" } }}| Message | details.source_id |
|---|---|
| The request | |
| Alignment must be sample_locked | โ |
| Each source | |
| Source is listed more than once | The repeated source |
| Unknown role 'host'; a source is a microphone, a mixdown or a bed | The source |
| A bed's array must be sound-capsule or sennheiser-ambeo | The bed |
| Only a bed has an array | The source |
| The roles together | |
| Microphones and a mixdown cannot be in the same session | โ |
| A session has at most one mixdown | The second mixdown |
| A session has at most one bed | The second bed |
| A bed needs at least one microphone | The bed |
| A session has at most four microphones | The fifth microphone |
| A session needs one to four microphones or one mixdown | โ |
| Each source's file | |
| Source not found | The source |
| Source is not ready; complete its upload first | The source |
| Source is already in another session | The source |
| A sennheiser-ambeo bed has 4 channels; this source has 8 | The bed |
| A microphone has 1 or 2 channels; this source has 3 | The source |
Lengths
The microphones and the bed must all be the same length, to within 2.7 milliseconds:
{ "error": { "code": "session_invalid", "message": "Source src_01a1446f8e8f7b23a4c06d1c3e5f7a90 is 10.0 milliseconds shorter than source src_01a1446f235c7448abbe096c9b9adf6c", "hint": "Trim the files to the same length, within 2.7 milliseconds, before uploading", "details": { "source_id": "src_01a1446f8e8f7b23a4c06d1c3e5f7a90" } }}A session can also be at most 3600 seconds long, and a longer one returns 400 validation_error.
Beds and ambisonics
A bed is the recording from an ambisonics microphone in the room. You need one for binaural mixes and ADM files, but the bed itself doesn't get a processed track.
Warning
A bed must be the A-format recording as it came off the array, and a 4-channel bed must also be a WAV file without a channel mask, but the API checks neither. If a 4-channel bed is FLAC, or a WAV with the quad channel mask (0x33) that the Ambisonics B-format export from Nomono Cloud writes, every binaural or ADM job on the session fails with "Processing failed", and running it again won't help. To fix it, upload the bed again as an A-format WAV without a channel mask and create a new session with it. B-format and AmbiX beds aren't supported, and a 4-channel one without the mask is processed as if it were A-format. An 8-channel sound-capsule bed can be WAV or FLAC.
The session object
| Field | What it holds |
|---|---|
session_id | The session's ID, starting ses_. |
status | Always ready. |
duration_s | The length of the longest source in seconds, the bed included. A job's minutes are based on it. |
sources | The sources in the order you sent them, each with source_id, role, label, array and the source object as source. |
alignment | Always sample_locked. |
retention_days | The retention_days you sent, or null. |
created_at | When the session was created. |
expires_at | When the session will be deleted, or null if it is kept until you delete it. |
GET /v1/sessions/{session_id} returns a session and GET /v1/sessions lists your sessions, newest first, in pages. Both need the jobs:write scope.
Retention
If you set retention_days, from 1 to 3650, the session is deleted that many days after it was created. If you don't, your organization's default retention applies when it has one, and otherwise the session is kept until you delete it.
Once expires_at has passed, we delete the session the same way a DELETE would, as soon as none of its jobs blocks the delete.
Deleting a session
DELETE /v1/sessions/{session_id} deletes the session together with its sources and the outputs of all its jobs, and returns 204.
curl -X DELETE "https://platform-api.nomono.co/v1/sessions/ses_01a14471a03b7c56a1e28d9f4b6c7d8e" \ -H "Authorization: Bearer $NOMONO_API_KEY"Afterwards the session's jobs return 404, but they still count in your usage. Any job whose processing hadn't started is cancelled and isn't billed.
A delete can return these errors:
| Status and code | Message | Hint | When |
|---|---|---|---|
409 conflict | Session has a job that is being processed | Delete the session once the job has finished | A job on the session has started processing, even if it still shows queued. |
409 conflict | Session has a failed job whose outputs may still arrive | Delete the session after 2026-10-17T09:41:58.996031+00:00 | A job on the session timed out less than 24 hours ago. |
Both 409 responses name the job in details.job_id:
{ "error": { "code": "conflict", "message": "Session has a job that is being processed", "hint": "Delete the session once the job has finished", "details": { "job_id": "job_01a14471b2d47f19b6a3c0e5d8f9a1b2" } }}A source in a session is deleted with the session, so DELETE /v1/sources/{source_id} on it returns 409 conflict, "Source is part of session {session_id}".