---
title: "Index an audio file (tags, content type, clipping/silence, metadata)"
method: POST
path: "/v1/signallab"
tags: ["SignalLab"]
---

# Index an audio file (tags, content type, clipping/silence, metadata)

`POST /v1/signallab`

## Request

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

Note: use /v1/signallab, not /v1/signallab/index. The hosting layer strips a
trailing /index from any path, so the older form redirects and then 404s for
clients that do not follow redirects.

## 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: regions, energyEnvelope and centroidEnvelope. 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.
  - `contentModel` 'v1' | 'v2': Which model gives the content type (voice, music, mixed, noise, unknown) and its confidence. v1 is the first model and is the default until 15 January 2027; v2 is the new one, much better on speech and music in the tests (see the status of signal.contentType at https://audiolab.tools/lenses). The same keys and types in both, only the values differ, and with v2 the evidence list contains model:v2. From 15 January 2027 the default becomes v2 and v1 stays selectable until at least 15 April 2027. Supported on signallab and analyze/profile.

## Response `200`

Index complete.

- SignalIndex: SignalLab indexer output (mirrors the engine SignalIndex 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
  - `fileName` string, required
  - `fileSizeKb` number
  - `format` string
  - `durationSec` number, required
  - `sampleRate` integer, required
  - `channels` integer, required
  - `bitDepthGuess` string: A guess from the file type (16/24-bit guess for WAV, lossy for compressed formats). Not read from the samples.
  - `peakDb` number
  - `rmsDb` number
  - `noiseFloorDb` number
  - `dcOffset` number
  - `hasClipping` boolean
  - `clippingRegions` integer
  - `silenceRegions` integer
  - `silenceTotalSec` number
  - `contentTypeGuess` 'voice' | 'music' | 'mixed' | 'noise' | 'silence' | 'unknown', required
  - `contentConfidence` number
  - `contentEvidence` string[]: The measurements that back the content type, as tags.
  - `beatStability` number, nullable: Deprecated alias of tempo confidence; one release, then gone.
  - `spectralFlatness` number: Flatness of the opening 10 s, 0 tonal to 1 noise-like.
  - `loopSeamRatio` number, nullable: Wrap-around jump divided by the mean sample-to-sample step. Under 3 inaudible, above 10 a click. Null on files too short to judge.
  - `edgeSilenceStartMs` number: Milliseconds under -60 dBFS at the start.
  - `edgeSilenceEndMs` number: Milliseconds under -60 dBFS at the end.
  - `inputSha256` string, nullable: SHA-256 of the submitted bytes, when supplied.
  - `bandwidthHz` number, nullable: Median per-block bandwidth over the non-silent blocks, Hz.
  - `lossySource` 'lossless' | 'lossy ~64k' | 'lossy ~128k' | 'lossy ~256k' | 'unknown': The wall a lossy encoder leaves, or unknown where two explanations collide (a 64 kbps wall and a sharp resample read the same).
  - `effectiveBitDepth` integer, nullable: Bits actually in use: 16 in a 24-bit container reads 16. Null under a thousand non-silent samples.
  - `upsampledFromHz` number, nullable: Likely original sample rate behind a resampler-shaped roll-off, or null.
  - `bandwidthSplices` integer: Bandwidth jumps of more than 3 kHz that hold for at least two seconds.
  - `toneProminenceDb` number, nullable: Most prominent tone against the masking noise in its critical band, dB (ISO 1996-2 annex C). Null on speech and under 0.17 s.
  - `toneFrequencyHz` number, nullable
  - `toneLabel` 'none' | 'audible' | 'prominent', nullable: Null where no tone was measured; see toneProminenceDb.
  - `thirdOctaveDb` object, nullable: IEC 61260 third-octave bands, 20 Hz to 20 kHz, dBFS RMS. Null under 0.17 s.
    - `centres` number[]
    - `db` number[]
  - `brightnessBucket` 'Dark' | 'Balanced' | 'Bright' | 'Very bright'
  - `dynamicsBucket` 'Flat' | 'Compressed' | 'Modern' | 'Dynamic'
  - `dominantBand` string: A rough band label from the zero-crossing rate. Not the band with the most energy.
  - `monophonicProbability` number: Left-right correlation, never below 0. Near 1 means mono in disguise. Not a probability.
  - `regions` TimelineRegion[]
    - `startSec` number
    - `endSec` number
    - `kind` 'voice' | 'silence' | 'music' | 'noise' | 'clipping'
    - `confidence` number
  - `totalRegions` integer: Regions the engine found, before any cap.
  - `returnedRegions` integer: Regions in this response. Lower than totalRegions when truncated.
  - `truncated` boolean: True when more than 500 regions were found and only the longest 500 are returned.
  - `energyEnvelope` number[]
  - `centroidEnvelope` number[]: Zero-crossing rate per frame, a rough brightness trace. Not a spectral centre in Hz.
  - `tags` 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)
