---
title: "Analyze loudness, dynamics, stereo, and spectrum"
method: POST
path: "/v1/mixlab/analyze"
tags: ["MixLab"]
---

# Analyze loudness, dynamics, stereo, and spectrum

`POST /v1/mixlab/analyze`

## Request

- Base URL: `https://audiolab.tools`
- URL: `https://audiolab.tools/v1/mixlab/analyze`
- Auth: HTTP bearer

Submit an audio file and get back the same JSON the in-browser MixLab
analyzer renders. Every analysis returns inline; there is no async path.
Files too long to decode are refused with 413 rather than queued.

## Request body

- object
  - `url` string, uri: Public http(s) URL to the audio file (alternative to multipart upload).
  - `objectPath` string: Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
  - `series` boolean: Send the curves as well: shortTermLufs, waveform and spectrum. Off by default since 22 September 2026, because they are ~98% of the payload and no answer needs them. Raw or multipart callers use ?series=true.
  - `round` boolean: Round the numbers to what the measurement is worth: dB and LUFS to 2 decimals, seconds to 3, shares to 3, Hz to 1. Same keys, same types, only fewer decimals. Off by default: without it you get the full precision, exactly as before. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
  - `measureStatus` boolean: Add one extra key, measureStatus, with the status (validated, proxy, beta, withdrawn, planned), the basis, how it works (dsp, model, mixed) and, where known, the margin of every measure in the answer. Off by default: without it the answer has no extra key. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.

## Response `200`

Analysis complete.

- AnalysisResult: MixLab analysis (mirrors the engine AnalysisResult type).
  - `measureStatus` MeasureStatus: Present only when the request asked for it with "measureStatus": true. For every measure in the answer that comes from a lens: how far to trust it. Keys are the field names of the answer (or the lens ids, for analyze/profile). Fields that are not measures (counts, flags, timings) have no entry.
    - `legend` string, uri: Where the five statuses are explained, and what you may and may not conclude from each.
    - `measures` object
  - `durationSec` number, required
  - `sampleRate` integer, required
  - `channels` integer, required
  - `integratedLufs` number, required: Integrated loudness (LUFS), BS.1770-4.
  - `reportUrl` string: Shareable numbers-only report page for this analysis (https://audiolab.tools/r/<id>). Present on every metered analysis response.
  - `shortTermLufsMax` number
  - `loudnessRange` number: LRA (LU).
  - `truePeakDb` number, required: True peak (dBTP).
  - `peakDb` number
  - `rmsDb` number
  - `crestFactorDb` number
  - `stereoWidth` number
  - `stereoCorrelation` number
  - `stereoBalanceDb` number: RMS left minus right, dB. Positive is left louder. 0 on mono.
  - `stereoLayout` 'mono' | 'dual-mono' | 'one-sided' | 'stereo' | 'silent': What kind of stereo file this is. dual-mono is two identical channels; one-sided is a dead channel.
  - `bassCorrelation` number, nullable: Correlation below 120 Hz after a 4th-order low-pass. Null on mono or without energy there. Below 0 the low end cancels in mono.
  - `momentaryLufsMax` number: Loudest 400 ms window (EBU Tech 3341 M), LUFS. Ungated.
  - `plrDb` number: Peak to loudness ratio: true peak minus integrated, LU.
  - `psrDb` number: Peak to short-term ratio: true peak minus the loudest 3 s window, LU.
  - `platformNormalisation` object[]: Per platform: the gain it applies, the true peak after it, and whether that clears the ceiling. Read the peak AFTER the gain.
    - `id` string
    - `label` string
    - `gainDb` number
    - `truePeakAfterDb` number
    - `ceilingDb` number
    - `verdict` 'ok' | 'over-ceiling' | 'under-target' | 'boost-not-published': ok: after whatever the platform does, the peak fits under the ceiling. over-ceiling: it does not, and that is knowable. under-target: the platform documents that it will play this below its reference level, because it caps the boost (Spotify) or does not raise quiet uploads at all (YouTube). boost-not-published: the file is quieter than the target and the platform does not publish whether it raises quiet uploads, so there is no peak-after-normalisation to report. gainGevraagdDb is the distance to their level and truePeakAtTargetDb is where the peak would land at that level, which is a property of the file rather than a claim about them.
    - `gainGevraagdDb` number: Gain the target would ask for, before any documented cap. Only where it differs from gainDb.
    - `onderDoelDb` number: How far below the target this will play. Only with under-target.
    - `truePeakAtTargetDb` number: Where the peak lands if the file is brought to the target level, by the platform or by hand. Only with boost-not-published.
    - `source` 'published' | 'measured': published: the platform documents the figure. measured: taken from outside measurements, so it can shift.
    - `measurementCaveat` string: How the platform's own measurement differs from integrated loudness. Present only where it does (atsc-broadcast).
    - `bron` 'published' | 'measured': Deprecated Dutch alias of source; removed after 2026-10-31.
    - `meetVerschil` string: Deprecated Dutch alias of measurementCaveat; removed after 2026-10-31.
  - `monoCompatible` boolean
  - `spectralCentroidHz` number
  - `spectralRolloffHz` number
  - `spectralFlatness` number
  - `bandEnergy` Band: Spectral band energies (relative).
    - `sub` number
    - `bass` number
    - `lowMid` number
    - `mid` number
    - `highMid` number
    - `presence` number
    - `air` number
  - `harshness` object
    - `score` number
    - `label` 'Low' | 'Medium' | 'High'
    - `band` string
  - `muddiness` object
    - `score` number
    - `label` 'Low' | 'Medium' | 'High'
  - `spectrum` object
    - `freqs` number[]
    - `mags` number[]
  - `waveform` number[]: Downsampled waveform peaks.
  - `shortTermLufs` number[]: Short-term loudness over time, at most 2000 points. Longer takes keep the PEAK per bucket, so a loud moment survives; seriesIntervalSec says how much time one point covers. Use /v1/mixlab/timeseries to choose the resolution yourself.
  - `seriesIntervalSec` number, nullable: Seconds covered by one point of shortTermLufs.
  - `fileName` string

## Other responses

- `400`: Malformed request, a URL we could not use, or a parameter that is not valid. Codes: url_not_allowed, url_fetch_failed, invalid_json, missing_input, invalid_parameter, batch_too_large, upload_not_found.
- `401`: Invalid or revoked API key. /v1/batch and /v1/usage always need a key; the analysis routes also run without one, as a small keyless trial. Codes: invalid_api_key.
- `402`: A limit of your plan was reached: the calls or the data of the month, or a preset that needs a paid plan. The body carries usage where it applies. Codes: quota_exceeded, data_quota_exceeded, profile_requires_paid_plan, voice_minutes_exhausted.
- `413`: File too large for the route, or a recording too long to decode. Codes: file_too_large, track_too_long.
- `422`: File could not be decoded as audio. Codes: unsupported_format, room_not_measurable.
- `429`: Too many requests this minute. See Retry-After. Codes: rate_limited.
- `500`: Something went wrong on our side. The details are logged and never sent to you. Codes: storage_unavailable, analysis_error.

---

[API](https://skmtc.dev/audiolab/apis/audiolab-api.md) · [All operations](https://skmtc.dev/audiolab/apis/audiolab-api/llms.txt) · [OpenAPI document](https://skmtc.dev/audiolab/apis/audiolab-api/revisions/69ff81f4f4ba?raw)
