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.
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_.
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-sdkMake 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'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)
}
}Verify webhooks
optionalSubscribe 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.
| Code | HTTP | Meaning |
|---|---|---|
| invalid_param | 400 | Request body failed validation. Inspect `error.param` for the offending field. |
| invalid_api_key | 401 | Missing, malformed, expired, or revoked key. |
| tier_insufficient | 403 | Music API requires Pro or above. Downgrades invalidate keys without revoking them. |
| insufficient_credits | 402 | Top up or upgrade your plan. |
| rpm_exceeded | 429 | 60 requests/minute per key. Honour the `Retry-After` header. |
| concurrent_limit_exceeded | 429 | Too many in-flight tasks. Wait for one to finish. |
| provider_error | 500 | Upstream 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.