Ship curated background music in any product — retail POS, fitness apps, digital signage, gym kiosks. REST + SDK + webhooks. Detailed playback reporting included.
The only background-music platform with a real public API, multi-tenancy, and per-stream playback reporting baked in.
Tens of thousands of curated tracks across 50+ genres, with per-track LUFS for consistent loudness across mixes.
One API key per operator. Each operator manages their own end-users with strict isolation. Built for B2B2C.
Pre-cache tracks to IndexedDB so playback survives weak Wi-Fi and short network outages.
Per-track, per-location playback logs with ISRC + timestamps, exportable for your own record-keeping.
Push event delivery with HMAC signatures + 8-attempt retry. No polling.
Cloudflare Workers edge, geographically distributed. Stream-token endpoint p95 < 50ms.
Stream your first track in under five minutes.
npm install @muzika/sdk
pnpm add @muzika/sdk
yarn add @muzika/sdk
Go to the operator console → API keys → New key. Save the secret — we show it once.
import { MuzikaClient } from '@muzika/sdk'; const muzika = new MuzikaClient({ apiKey: process.env.MUZIKA_KEY }); // Browse the catalog const { data: tracks } = await muzika.catalog.listTracks({ genre: 'Greek Hits', limit: 10 }); // Mint a signed URL (5 min TTL) const { url } = await muzika.stream.getUrl({ track_id: tracks[0].id }); // Play in browser const audio = new Audio(url); audio.play();
await muzika.events.logPlayback({ store_token: 'store_token_xxx', events: [{ type: 'play_start', track_id: tracks[0].id, track_title: tracks[0].title, track_artist: tracks[0].artist, client_ts: new Date().toISOString(), }], });
All endpoints are versioned at /v1 and protected by Bearer API key auth.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/catalog/tracks | Browse + search catalog |
| GET | /v1/catalog/tracks/:id | Single track |
| GET | /v1/catalog/playlists | Browse playlists |
| GET | /v1/catalog/playlists/:id/tracks | Resolved track list (composites expanded) |
| POST | /v1/stream/token | Signed audio URL for <audio src> |
| GET | /v1/stores | List operator's stores |
| POST | /v1/stores | Create store |
| POST | /v1/stores/:id/command | Push remote command (refresh / skip / pause / volume) |
| POST | /v1/events/playback | Bulk-ingest playback events (up to 500/req) |
| GET | /v1/sync/manifest | Offline-first download manifest |
| POST | /v1/webhooks/endpoints | Register a webhook URL |
| GET | /v1/webhooks/deliveries | Per-endpoint delivery log |
| GET | /v1/operators/me | Profile + plan tier |
| POST | /v1/operators/me/api-keys | Create API key (secret shown once) |
Want the full OpenAPI 3.1 spec? Request API access → · use it with
openapi-typescript for typed clients in any language.
Use a typed wrapper instead of writing fetch calls by hand.
Browser, Node ≥18, Bun, Cloudflare Workers. ESM + CJS. Built-in retry, custom transport injection, browser-only offline-first cache.
import { MuzikaClient } from '@muzika/sdk'; const muzika = new MuzikaClient({ apiKey: 'mk_live_…' }); // .catalog .stream .stores .events .sync .webhooks .operators
Native SDKs for the headless-streamer use case + mobile apps.
Push delivery of events to your endpoint. Replaces polling. HMAC-signed payloads.
store.online — a streamer connectedstore.offline — streamer quiet > 5 minstore.dual_use_blocked — duplicate device detectedplayback.event_batch — track play_start (batched)sync.completed — offline pre-cache filledquota.warning — 80% of rate-limit reachedimport { verifyWebhookSignature } from '@muzika/sdk'; app.post('/webhook', async (req, res) => { const body = await req.text(); const ok = await verifyWebhookSignature({ body, signatureHeader: req.headers.get('X-Muzika-Signature'), timestampHeader: req.headers.get('X-Muzika-Timestamp'), secret: process.env.MUZIKA_WEBHOOK_SECRET, }); if (!ok) return res.status(401).end(); // ... process the event });
Want the webhook guide (retry semantics + idempotency)? Ask us →
All requests use a Bearer API key. Keys are tenant-scoped — they only see their own operator's data.
Authorization: Bearer mk_live_4f2a8c1b.x7Y3Q…long-secret…
X-End-User-Id: cafe-elmara-tlv # optional — passed through to audit
Generate keys in the console. Rotate via
POST /v1/operators/me/api-keys/:id/rotate — old key invalidated, new returned in one round-trip.
Per-operator quotas. Soft warning headers fire at 80%; 429 with Retry-After at the cap.
| Tier | Requests / minute | Streams / day | Storage |
|---|---|---|---|
| starter | 60 | 5,000 | 10 GB |
| growth | 300 | 50,000 | 100 GB |
| enterprise | 2,000 | 500,000 | negotiated |