# Beatra API — Text to music

> Generate music with vocals or instrumental-only from a text description.
> Self-contained integration guide for AI coding assistants.
> Human-readable page: https://docs.beatra.ai/en/docs/capabilities/music/text-to-music

- Base URL: `https://api.beatra.ai/v1`
- Auth: `Authorization: Bearer <BEATRA_API_KEY>` — create keys in the console at https://console.beatra.ai (Developer → API keys)
- Headers: `Content-Type: application/json`; send `Idempotency-Key` (stable UUID) on create-style POSTs (24h dedupe window); optional `X-Request-Id` is echoed back.
- Interaction model: async task — create returns `202` with a `task_id`; poll `GET /v1/tasks/{task_id}` until terminal status (`succeeded` / `failed` / `canceled`), or pass `callback_url` to be notified (see appendix).

---

## Primary agent path

Use the Universal Skill with the MCP tool `beatra.music.generate`. The tool is
billable and returns an asynchronous task.

1. Settle the outcome: vocal song or instrumental, mood, and whether the user
   supplies lyrics.
2. If a model, control, constraint, or price matters, call `beatra.models.list`
   with `capability: "text_to_music"`. Otherwise use `model: "auto"` or omit
   `model`.
3. Create one opaque `client_request_id` and submit the final arguments once.
4. Poll the returned task with `beatra.tasks.get` until it is terminal.

## Tool arguments

```json
{
  "prompt": "Upbeat city pop for a summer evening drive",
  "instrumental": false,
  "lyrics": "Evening wind sweeps across the rooftop\nNeon lights flicker on one by one",
  "client_request_id": "music-text-opaque-1"
}
```

`instrumental: true` generates instrumental-only music and forbids `lyrics`.

## Models, controls, and cost

Common controls are `prompt`, `lyrics`, `instrumental`, `title`, and
`model_options`. Use each only according to the selected model's metadata.

`beatra.models.list` is the current source for selectable models, prompt and
lyrics length limits, vocal-lyrics requirements, model-family options, and the
per-task customer price. Do not copy a model catalog or price table into an
agent prompt.

Model-family options under `model_options.*` require an explicit `model`;
unsupported combinations fail validation instead of being silently ignored.
Music is prepaid and billed per successful task at the selected model's
catalog price.

## Task status and recovery

`queued` and `running` are not failures. Keep polling the same `task_id`; never
submit a replacement because work is still running. On a lost create response,
retry the identical arguments with the same `client_request_id`. If any input
changes, use a new ID. Failed tasks automatically refund the charged credits.

A successful task returns one or more `clips[]`, each with a title, optional
lyrics, and an audio artifact. Artifact URLs are CDN addresses — copy them to
your own storage promptly.

## REST API

Direct protocol integrations may use `POST /v1/music/text-to-music` and the
shared task endpoints. Follow the generated [API operation](https://docs.beatra.ai/en/docs/api-reference/operations/music/text_to_music_v1_music_text_to_music_post).
Skill + MCP is the recommended integration; use REST for custom, non-agent
applications.

---

## Appendix: shared contract for async tasks

### Callbacks (optional)

Pass `callback_url` (HTTPS) when creating the task. After the task reaches a
    terminal state Beatra POSTs to it and expects a 2xx within 10 seconds:

```json
{ "event_id": "evt_...", "event_type": "task.succeeded", "event_time": "...", "task": { "...": "full task envelope" } }
```

Headers: `X-Event-Id` (stable across retries — use for idempotent dedupe),
`X-Delivery-Id`, `X-Delivery-Attempt`, `X-Task-Id`, `X-Event-Type`, `X-Timestamp`,
and, for signed delivery, `X-Signature-Key-Id` plus
`X-Signature: t=<unix_ts>,v1=<hex>` where `v1 = HMAC-SHA256(signing_secret, "<unix_ts>." + raw_body)`.
Callback signing keys are independent of API keys and are managed through the
account signing-key API or Console. Pass `callback_signing_key_id` with
`callback_url` for signed delivery, or omit it for unsigned delivery. The
secret is returned once when a signing key is created or rotated. Reject
timestamps more than 300s off. Retries on failure: 1m / 5m / 30m / 2h / 12h.
Polling `GET /v1/tasks/{task_id}` always remains the source of truth.

### Billing

Credits are an independent billing unit with no fixed exchange rate to a fiat
currency. Media tasks are charged up-front at creation; insufficient balance returns `402 insufficient_balance`
and no task is created. Failed tasks are refunded automatically — see
`billing.charged_credits` / `billing.refunded_credits` in the task envelope.

### Errors

Every non-2xx response uses one envelope:

```json
{ "error": { "code": "...", "type": "...", "message": "...", "retryable": false, "request_id": "req_..." } }
```

Retry only when `retryable` is `true`, with exponential backoff and the SAME
`Idempotency-Key`. `429` responses include `X-RateLimit-*` headers.
