# Audio Intelligence API

Nech.PL APIs · api.nech.pl/audio/v1 · Getting Started

NECH.PL
APIs

Stem-aware audio analysis as simple HTTP calls — emotion (valence/arousal), a ~35-dim feature stack, per-sample role, loop grading, onsets/tempo, render-ready waveform & spectrogram (FFT-as-a-service), BS.1770 loudness, and naming. Upload a clip, get JSON. Identical audio is cached server-side, so repeats are free.

Your API key (Bearer) — scope api:*
__NECHPL_TOKEN__
Your npm read token — to install @nech/api from npm.nech.pl
__NECH_NPM_TOKEN__
Keep both secret — send only over a private channel. Anyone with the API key can call the API as you. Lost/leaked? Ping ParVagues and they're revoked & reissued in seconds.

## 1 · Talk to it

### Base URL & auth

- Base: https://api.nech.pl/audio/v1
- Header: Authorization: Bearer <key>
- Body: multipart/form-data, one file field (audio)
- Returns: JSON. Cache state in X-Nech-Cache: hit|miss

### Your access

Your key carries scope api:* — full access to every Nech.PL API, present and future. Only /healthz is public; the interactive docs & spec need an api:docs scope, which your api:* key already covers.

### 📖 Docs & spec (live)

- Swagger UI: https://api.nech.pl/audio/v1/docs
- OpenAPI JSON: https://api.nech.pl/audio/v1/openapi.json

Both are bearer-gated — open them with your key (e.g. a browser extension that sends Authorization: Bearer, or curl -H). Generate a client in any language from the spec.

### First call (curl)

    B=https://api.nech.pl/audio/v1

    # is it up? (no key needed)
    curl $B/healthz

    # who am I?
    curl -H "Authorization: Bearer $KEY" $B/me

    # analyse a clip
    curl -H "Authorization: Bearer $KEY" \
      -F file=@track.wav $B/analyze/emotion

## 2 · Endpoints

Method & path | Returns
--- | ---
POST /analyze/emotion | valence/arousal + top emotions
POST /features | ~35-dim feature stack (spectral, MFCC, chroma/key, rhythm)
POST /analyze/samples | per-sample EDA + measured role (percs/bass/melodic/tops/atmos)
POST /analyze | emotion + features + sample role in one call
POST /grade | mechanical loop quality: 0–1 + S/A/B/C/D tier + flags
POST /onsets | onset times + tempo + onset rate
POST /waveform | [min,max] peaks + 0–1 RMS envelope (audio-reactive visuals)
POST /spectrum | downsampled spectrogram, bands×frames 0–1 (FFT-as-a-service)
POST /loudness | BS.1770 LUFS + sample/true peak + gain-to-target (−14/−9)
POST /naming | convention-compliant sample name from the measured role
POST /sources | fetch a URL's audio (yt-dlp) → 44.1k WAV, as a job → 202 {job_id}. ✨ the front door of the YouTube→emotion pipeline
GET /jobs/{id} · DELETE | poll an async job (status/progress/result) · cancel it
GET /artifacts/{cid}/{name} | download a stored artifact (fetched source WAV; later stems/loops). Range-capable
POST /separate | 503 stem separation — GPU runner pending; code against it now
GET /healthz | public: liveness probe (no token)
GET /docs · /openapi.json | interactive docs · spec — need an api:docs scope (your api:* token covers it)

## 3 · ✨ The YouTube → emotion pipeline

Hand the API a URL — YouTube, SoundCloud, Bandcamp, any http(s) yt-dlp supports — and read its mood. /sources fetches + transcodes to WAV as a background job; poll /jobs/{id}, grab the artifact, run /analyze/emotion. Re-fetching the same URL is instant (cached server-side).

    B=https://api.nech.pl/audio/v1 ; H="Authorization: Bearer $KEY"

    # 1 · fetch a URL's audio as a job  ->  202 { job_id }
    JID=$(curl -s -H "$H" -H "Content-Type: application/json" \
      -d '{"url":"https://youtu.be/<id>"}' $B/sources | jq -r .job_id)

    # 2 · poll until done  ->  { content_id, artifact_ref }
    REF=$(curl -s -H "$H" $B/jobs/$JID | jq -r .result.artifact_ref)

    # 3 · download the WAV   4 · read its emotion
    curl -s -H "$H" $B/artifacts/$REF -o src.wav
    curl -s -H "$H" -F file=@src.wav $B/analyze/emotion | jq .emotion
    # -> { valence: 0.62, arousal: 0.78, top: ["energetic","uplifting", …] }

Same pipeline in TypeScript with @nech/api: submitSource → getJob (poll) → fetch artifact → analyzeEmotion. Heavier engines (/separate stems, loops) follow the same job shape.

## 4 · TypeScript / Vercel — @nech/api (generated)

The official client is generated from the OpenAPI spec, so it never drifts. Install from the private registry (needs your npm read token), then import the per-API subpath — runs on Node 18+, Vercel Functions and the Edge.

    # .npmrc
    @nech:registry=https://npm.nech.pl/
    //npm.nech.pl/:_authToken=${NECH_NPM_TOKEN}

    $ npm i @nech/api

    import { AudioApi, Configuration } from "@nech/api/audio";

    const audio = new AudioApi(new Configuration({
      basePath: "https://api.nech.pl/audio/v1",
      accessToken: process.env.NECH_TOKEN!,
    }));

    const clip = await fetch(trackUrl).then(r => r.blob());
    const mood = await audio.analyzeEmotion({ file: clip });  // { emotion: { valence, arousal, … } }
    const spec = await audio.spectrum({ file: clip, bands: 64, frames: 200 });

## 5 · Good to know

- Caching is your friend. Same bytes → same result, served instantly. Hash-addressed; nothing to manage.
- Limits. Uploads up to ~40 MB; a burst rate-limit + monthly quota apply (generous — ask if you hit them).
- Errors. 401 bad/missing key · 403 out of scope/quota (X-Reason) · 413 too big · 503 compute pending (separation).
- Privacy. Audio is processed transiently and the cache is evictable — no long-term storage of your files.

## 6 · Support

This is hand-built by ParVagues for the hydra-live-hexa Studio. Anything weird, a number that looks off, an endpoint you wish existed — just shout. Fast iterations, that's the point.

Welcome aboard. ⛵

Nech.PL APIs · Audio Intelligence v1 · api.nech.pl Generated __GENERATED__