Quickstart

Generate AI music
programmatically.

The Lacuna Music API ships with a typed TypeScript SDK and CLI. Five steps below take you from no account to a finished, hosted audio file.

1

Get an API key

Music API access requires the Pro plan or above. From your dashboard, create a key — it's shown once at creation; copy it into a secrets manager immediately. Keys begin with lyr_live_.

2

Install the SDK

The official SDK is lacuna-sdk — typed TypeScript client on Node 18+. Prefer the command line? Install lacuna-toolkit instead.

npm install lacuna-sdk
# or
pnpm add lacuna-sdk
# or
yarn add lacuna-sdk
3

Make your first request

Create a task. Credits are deducted up-front and refunded automatically if the upstream provider fails.

import Lacuna from 'lacuna-sdk'

const lacuna = new Lacuna({ apiKey: process.env.LACUNA_API_KEY })

const task = await lacuna.music.generations.create({
  style: 'lofi hip hop, mellow piano, 70 bpm',
  title: 'Late Night Study',
  instrumental: true,
})

console.log(task.id, task.status) // 'cm123abc...' 'pending'
4

Wait for completion

Tasks run asynchronously. waitFor polls until the task reaches a terminal state. For production traffic, prefer webhooks — see step 5.

const finished = await lacuna.music.generations.waitFor(task.id, {
  pollInterval: 5_000, // poll every 5s
  timeout: 600_000,    // up to 10 minutes
})

if (finished.status === 'ready') {
  for (const track of finished.tracks) {
    console.log(track.audio_url, track.duration, track.lyrics)
  }
}
5

Verify webhooks

optional

Subscribe to job.completed and job.failed events and verify their HMAC-SHA256 signatures. The SDK ships a verifier with replay protection.

// Next.js (App Router) — app/api/webhooks/lacuna/route.ts
import { Webhooks } from 'lacuna-sdk/webhooks'

export async function POST(request: Request) {
  const body = await request.text()
  const event = Webhooks.constructEvent(
    body,
    request.headers.get('x-lacuna-signature'),
    process.env.LACUNA_WEBHOOK_SECRET!,
  )

  if (Webhooks.isJobCompleted(event)) {
    // event.data.tracks is fully typed
  }

  return new Response(null, { status: 200 })
}

Errors & rate limits

Every error response carries an OpenAI-style envelope — { error: { type, code, message, param } }. The SDK exposes typed subclasses (RateLimitError, InsufficientCreditsError, …) so your handlers can be precise.

CodeHTTPMeaning
invalid_param400Request body failed validation. Inspect `error.param` for the offending field.
invalid_api_key401Missing, malformed, expired, or revoked key.
tier_insufficient403Music API requires Pro or above. Downgrades invalidate keys without revoking them.
insufficient_credits402Top up or upgrade your plan.
rpm_exceeded42960 requests/minute per key. Honour the `Retry-After` header.
concurrent_limit_exceeded429Too many in-flight tasks. Wait for one to finish.
provider_error500Upstream failure. Credits are refunded automatically.

429 responses always include a Retry-After header (seconds). The SDK retries 429 / 5xx responses up to twice by default with jittered exponential backoff.

Need the full reference?

Every endpoint, every parameter, schemas, and webhook payloads.

Open API reference