MuzikA developers

Music-as-a-Service
for your app.

Ship curated background music in any product — retail POS, fitness apps, digital signage, gym kiosks. REST + SDK + webhooks. Detailed playback reporting included.

Quickstart → Read the API reference

Why MuzikA

The only background-music platform with a real public API, multi-tenancy, and per-stream playback reporting baked in.

🎧

Tier 1 catalog

Tens of thousands of curated tracks across 50+ genres, with per-track LUFS for consistent loudness across mixes.

🏢

Multi-tenant by design

One API key per operator. Each operator manages their own end-users with strict isolation. Built for B2B2C.

📡

Offline-first SDK

Pre-cache tracks to IndexedDB so playback survives weak Wi-Fi and short network outages.

📊

Detailed playback reports

Per-track, per-location playback logs with ISRC + timestamps, exportable for your own record-keeping.

🔔

Webhooks

Push event delivery with HMAC signatures + 8-attempt retry. No polling.

Sub-100ms p95

Cloudflare Workers edge, geographically distributed. Stream-token endpoint p95 < 50ms.

Quickstart

Stream your first track in under five minutes.

1. Install the SDK

npm
pnpm
yarn
npm install @muzika/sdk
pnpm add @muzika/sdk
yarn add @muzika/sdk

2. Create an API key

Go to the operator console → API keys → New key. Save the secret — we show it once.

3. Play a track

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();

4. Log playback events

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(),
  }],
});

API reference

All endpoints are versioned at /v1 and protected by Bearer API key auth.

MethodPathPurpose
GET/v1/catalog/tracksBrowse + search catalog
GET/v1/catalog/tracks/:idSingle track
GET/v1/catalog/playlistsBrowse playlists
GET/v1/catalog/playlists/:id/tracksResolved track list (composites expanded)
POST/v1/stream/tokenSigned audio URL for <audio src>
GET/v1/storesList operator's stores
POST/v1/storesCreate store
POST/v1/stores/:id/commandPush remote command (refresh / skip / pause / volume)
POST/v1/events/playbackBulk-ingest playback events (up to 500/req)
GET/v1/sync/manifestOffline-first download manifest
POST/v1/webhooks/endpointsRegister a webhook URL
GET/v1/webhooks/deliveriesPer-endpoint delivery log
GET/v1/operators/meProfile + plan tier
POST/v1/operators/me/api-keysCreate 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.

Official SDKs

Use a typed wrapper instead of writing fetch calls by hand.

JavaScript / TypeScript

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

Coming soon

Native SDKs for the headless-streamer use case + mobile apps.

  • Android (Kotlin) — Q4 2026
  • iOS (Swift) — Q1 2027
  • Python — Q1 2027

Webhooks

Push delivery of events to your endpoint. Replaces polling. HMAC-signed payloads.

Events

Verify a signature (Node)

import { 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 →

Authentication

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.

Rate limits

Per-operator quotas. Soft warning headers fire at 80%; 429 with Retry-After at the cap.

TierRequests / minuteStreams / dayStorage
starter605,00010 GB
growth30050,000100 GB
enterprise2,000500,000negotiated