> For the complete documentation index, see [llms.txt](https://docs.auray.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.auray.ai/documentation/prompting-music.md).

# Prompting music

The prompt is the largest single thing standing between a generic loop and a song worth keeping. The model is the same either way.

Two fields go in, and they do different jobs.

| Field    | What goes in it                                 | What it decides                         |
| -------- | ----------------------------------------------- | --------------------------------------- |
| `prompt` | Genre, tempo, key, instruments, vocal character | How the song sounds                     |
| `lyrics` | The words that are sung, with structure tags    | What is sung, and the shape of the song |

Leave `lyrics` out and you get an instrumental.

{% hint style="warning" %}
The JSON on this page describes `POST /v1/music`, which is switched off on this deployment. Every `/v1` route answers `503 api_disabled` before your key is even parsed, so a valid key and an invalid one look the same there. None of the advice below depends on the API — the Music app takes the same two fields, and every rule here applies to both.
{% endhint %}

**Nothing ever sends empty lyrics.** The pipeline refuses an empty string outright, so an instrumental is dispatched with `[instrumental]` — a structure tag the model already recognises — rather than with nothing. You send no `lyrics` field; the service supplies that.

**The limits are 5,000 characters of prompt and 10,000 of lyrics,** measured after trimming. Past either, the request is refused with `400 prompt_too_long` or `400 lyrics_too_long`. The Music app's two panes stop accepting characters at exactly those numbers, so you cannot reach the refusal from the desktop — you can only reach it from your own code.

## Writing the prompt

The prompts that work read like a producer's brief: specific, technical, in order.

{% stepper %}
{% step %}

### State the facts first

`Genre`, `BPM` and `Key`. Three labelled values, one sentence. The key is the one people leave out, and it is the one that gives the model a harmonic anchor.
{% endstep %}

{% step %}

### Say what it should feel like

One clause. Warm, driving, nostalgic, tense. This is where the adjectives belong, and it is the only place they belong.
{% endstep %}

{% step %}

### Describe the voice, or say there is none

Kind of voice, character, technique — `soft female lead, close and breathy`. Writing `Vocals: none` in an instrumental prompt is worth the four words.
{% endstep %}

{% step %}

### Describe the arrangement as a development

Not which instruments exist, but which arrive when. This is the part of the prompt the model has the most room to act on.
{% endstep %}
{% endstepper %}

Which comes out as:

```
Genre: <genre>. BPM: <tempo>. Key: <key>.
<Mood and emotional direction>.
Vocals: <kind of voice, character, technique>.
Arrangement: <instruments, when they enter, how it develops>.
```

A complete one:

```
Genre: acoustic pop. BPM: 96. Key: C major. Warm and intimate, building
gently into the chorus. Vocals: soft female lead, close and breathy, light
stacked harmonies in the chorus. Arrangement: fingerpicked guitar and soft
piano; brushed drums and upright bass enter in the chorus.
```

Every sentence there adds something none of the others carry, and the `Arrangement` line describes a **development** — which instrument arrives in which section — rather than listing what is in the room.

### Six dimensions worth naming

| Dimension       | Values that work                                                                                               |
| --------------- | -------------------------------------------------------------------------------------------------------------- |
| **Genre**       | acoustic pop, lofi hip hop, bossa nova, synthwave, indie rock, orchestral, EDM, jazz, R\&B, dangdut, keroncong |
| **Tempo**       | `BPM: 82` (slow) · `BPM: 120` (medium) · `BPM: 140` (fast)                                                     |
| **Key**         | `C major` (bright) · `A minor` (melancholy) · `E♭ major` (warm)                                                |
| **Mood**        | warm, nostalgic, driving, melancholic, triumphant, dreamy, tense                                               |
| **Vocals**      | soft female lead, raspy male baritone, breathy, belted, whispered, layered harmonies                           |
| **Arrangement** | which instruments, when they enter, how the dynamics move                                                      |

### Describe the development, not the instrument list

The model is strong at long-range structure. A list gives it nothing to do with that.

Weak:

```
Piano, drums, bass, guitar. Pop song.
```

Strong:

```
Genre: indie pop. BPM: 110. Starts with solo piano and vocals; drums and bass
enter at the first chorus; a guitar countermelody appears in the second verse;
final chorus is full band with layered harmonies, then strips back to piano
for the outro.
```

## Writing the lyrics

Wrap each section in a square-bracket tag.

```
[intro]

[verse]
Morning light filtering through the pine
Every quiet street is yours and mine

[chorus]
Softly the world begins to breathe
Everything I need is here with me

[verse]
Afternoon shadows on the kitchen floor
Nothing that I'm looking for anymore

[chorus]
Softly the world begins to breathe
Everything I need is here with me

[bridge]
And if the season turns again
I will still be here

[chorus]
Softly the world begins to breathe

[outro]
```

The tags it reads:

```
[intro]  [verse]  [pre-chorus]  [chorus]  [bridge]  [outro]  [instrumental]  [hook]
```

`[instrumental]` is the one this stack relies on directly, to ask for a song with no voice in it. The Music app's own hint names three — `[verse]`, `[chorus]` and `[bridge]` — because those are the three that shape almost every song anybody writes here.

{% hint style="info" %}
The model card calls the tags **guidance, not a guarantee**. The model can read them loosely. Treat a tag as strong direction rather than an instruction it must obey.
{% endhint %}

### Match the lyrics to the length

This is the most common mistake. Too many words for a short song and the vocal is rushed; too few for a long one and you get instrumental stretches nobody asked for.

| Duration           | Structure that fits                               |
| ------------------ | ------------------------------------------------- |
| 30 seconds         | 1 verse + 1 chorus                                |
| 60 seconds         | verse + chorus + verse + chorus                   |
| 120 seconds        | verse + chorus + verse + chorus + bridge + chorus |
| 180 seconds and up | The full thing, with an intro and an outro        |

The rough rule: **one section, verse or chorus, is 15 to 20 seconds.**

### What the length itself costs you

`duration_seconds` runs from 10 to 300. Outside that it is refused with `400 duration_out_of_range` rather than clamped, because the duration is the entire price and quietly charging for a different length would make the quote a lie.

Your plan caps it lower: 60 seconds on Pro, 180 on Max, 300 on Ultimate. Asking for more than your ceiling is `403 duration_not_in_plan`, which is a different refusal from the one above and has a different fix. The free plan cannot generate music at all — `403 plan_has_no_music` — and a free API key cannot generate anything at all, with `403 plan_has_no_api_generate`. Neither is a rate limit, so retrying never helps.

Every plan that can make music can also sing. There is a `lyrics_not_in_plan` refusal in the code for a plan with music but no vocals; no plan is shaped that way today, so you will not meet it.

**The duration is a target, not a promise.** The model stops when the song feels finished, so a 300-second request can come back at 120. You are charged on what you asked for — two credits, plus one for every four seconds — and when the audio arrives short, the per-second part of the difference is refunded.

Rendering takes roughly 1.78 times the length of the song, plus about half a minute of model loading: 138 seconds of waiting for a 60-second song, which is what the submit response quotes as `expected_seconds`. That ratio was measured over two renders through this stack rather than taken from the model's own benchmark, which claims 1.15x and does not hold here. Two renders is two renders — treat it as provisional.

## Instrumentals

Send no `lyrics` at all, and make the prompt more descriptive to fill the space a voice would have taken.

```json
{
  "prompt": "Genre: ambient electronic. BPM: 70. Key: D minor. Spacious and contemplative. No vocals. Arrangement: warm analog pad foundation, sparse piano melody entering after 15 seconds, subtle field recordings of rain, gentle sub bass pulse. Gradual build in density toward the middle, then a slow decay into silence.",
  "duration_seconds": 120
}
```

Writing `No vocals` into the prompt as well is redundant on paper and helps in practice.

## Seeds

The same prompt, lyrics, duration and seed give you the same audio back. A seed is a whole number from 0 to 2,147,483,647.

```json
{ "prompt": "...", "lyrics": "...", "duration_seconds": 60, "seed": 42 }
```

Out of that range, or not an integer at all, is **ignored rather than refused** — the request still runs, with a random seed. That is deliberate: a bounds check declared in the schema would make generated clients reject something this API accepts.

{% hint style="danger" %}
**Nothing gives the seed back.** If you do not choose one, the model picks a random seed inside the container, and no response ever reports it: not the submit envelope, not `GET /v1/jobs/{id}`, and the Music app has no seed field at all. A song generated without a seed cannot be reproduced by anyone, including us. Generate the number yourself and store it beside the prompt.
{% endhint %}

Two things a seed you kept is good for:

* **Variations.** Hold the seed, move the prompt. The results sound related.
* **Alternatives.** Hold the prompt, move the seed. Rendering three at once needs a plan that allows three songs in flight — Pro allows one, Max two, Ultimate three; past that you get `429 too_many_jobs`, and the fix is to wait rather than to resubmit.

## Examples that work

### Lofi hip hop

```json
{
  "prompt": "Genre: lofi hip hop. BPM: 82. Key: F minor. Mellow, nostalgic, slightly melancholic. Vocals: none. Arrangement: dusty Rhodes piano chords with vinyl crackle, laid-back boom bap drums with soft snare, warm upright bass, occasional muted trumpet phrase. Tape saturation throughout.",
  "duration_seconds": 90
}
```

### Acoustic pop with a voice

```json
{
  "prompt": "Genre: acoustic pop. BPM: 96. Key: C major. Warm and intimate, building gently into the chorus. Vocals: soft female lead, close and breathy, light stacked harmonies in the chorus. Arrangement: fingerpicked guitar and soft piano; brushed drums and upright bass enter in the chorus.",
  "lyrics": "[verse]\nMorning light filtering through the pine\nEvery quiet street is yours and mine\n\n[chorus]\nSoftly the world begins to breathe\nEverything I need is here with me",
  "duration_seconds": 60
}
```

That one, sent three ways:

{% tabs %}
{% tab title="curl" %}

```bash
curl https://api.auray.ai/v1/music \
  -H "Authorization: Bearer $AURA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Genre: acoustic pop. BPM: 96. Key: C major. Warm and intimate, building gently into the chorus. Vocals: soft female lead, close and breathy, light stacked harmonies in the chorus. Arrangement: fingerpicked guitar and soft piano; brushed drums and upright bass enter in the chorus.",
    "lyrics": "[verse]\nMorning light filtering through the pine\nEvery quiet street is yours and mine\n\n[chorus]\nSoftly the world begins to breathe\nEverything I need is here with me",
    "duration_seconds": 60,
    "seed": 42
  }'
```

{% endtab %}

{% tab title="Node" %}

```javascript
const response = await fetch("https://api.auray.ai/v1/music", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AURA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt:
      "Genre: acoustic pop. BPM: 96. Key: C major. Warm and intimate, building " +
      "gently into the chorus. Vocals: soft female lead, close and breathy, light " +
      "stacked harmonies in the chorus. Arrangement: fingerpicked guitar and soft " +
      "piano; brushed drums and upright bass enter in the chorus.",
    lyrics:
      "[verse]\nMorning light filtering through the pine\n" +
      "Every quiet street is yours and mine\n\n" +
      "[chorus]\nSoftly the world begins to breathe\n" +
      "Everything I need is here with me",
    duration_seconds: 60,
    seed: 42,
  }),
});
```

{% endtab %}

{% tab title="Python" %}

```python
import os
import requests

response = requests.post(
    "https://api.auray.ai/v1/music",
    headers={"Authorization": f"Bearer {os.environ['AURA_API_KEY']}"},
    json={
        "prompt": (
            "Genre: acoustic pop. BPM: 96. Key: C major. Warm and intimate, building "
            "gently into the chorus. Vocals: soft female lead, close and breathy, light "
            "stacked harmonies in the chorus. Arrangement: fingerpicked guitar and soft "
            "piano; brushed drums and upright bass enter in the chorus."
        ),
        "lyrics": (
            "[verse]\nMorning light filtering through the pine\n"
            "Every quiet street is yours and mine\n\n"
            "[chorus]\nSoftly the world begins to breathe\n"
            "Everything I need is here with me"
        ),
        "duration_seconds": 60,
        "seed": 42,
    },
)
```

{% endtab %}
{% endtabs %}

### Synthwave

```json
{
  "prompt": "Genre: synthwave. BPM: 118. Key: A minor. Driving and cinematic, neon-lit night drive energy. Vocals: none. Arrangement: pulsing analog bass arpeggio, gated reverb drums, soaring lead synth melody with heavy chorus effect, lush pad chords. Builds intensity every 16 bars.",
  "duration_seconds": 120
}
```

### Bossa nova

```json
{
  "prompt": "Genre: bossa nova. BPM: 128. Key: D major. Relaxed and sophisticated, late afternoon warmth. Vocals: gentle male voice, conversational and slightly behind the beat. Arrangement: nylon-string guitar with classic bossa comping pattern, brushed drums, warm upright bass, subtle vibraphone accents.",
  "lyrics": "[verse]\nSlow the afternoon comes down\nGolden on the empty town\n\n[chorus]\nAnd I am not in any hurry now",
  "duration_seconds": 90
}
```

### Indie rock

```json
{
  "prompt": "Genre: indie rock. BPM: 148. Key: E major. Urgent and anthemic, festival energy. Vocals: male lead, raw and slightly strained at the top of the range, gang vocals on the chorus. Arrangement: driving distorted guitars, punchy drums with open hi-hats, melodic bassline. Chorus opens up wide with layered guitars.",
  "lyrics": "[verse]\nWe were running out of daylight\nCounting all the ways to stay\n\n[chorus]\nHold on, hold on\nWe are not done yet",
  "duration_seconds": 100
}
```

## What gets refused

Two rules run over the prompt and lyrics together, before any GPU is allocated.

**Asking for a specific person's voice** is `prohibited_voice_cloning`. The patterns catch "sounds like" followed by a name, "clone the voice", "imitate the vocal", "deepfake", and the Indonesian equivalents. The licence this model is served under requires the check, and it is one of the few places a narrow rule is the right shape: blocking the word "voice" outright would kill legitimate prompts like `warm vocal texture`.

**Illegal content** is `prohibited_content`, and covers what you would expect it to.

Both come back as `400` with `refunded: true` — the credits are taken at submit and given straight back when the dispatch is refused. The `message` beside them is the generic "The request was rejected."; the `error` code is the part worth reading. Describe the characteristic instead of the person: `bright female pop vocal with conversational phrasing`.

## Common mistakes

**A prompt that is too short.** `"sad piano song"` produces something generic. Three or four specific sentences produce something you would put in front of someone.

**Lyrics that do not fit the length.** Five verses in a 30-second clip get cut off or rushed through.

**Naming an artist.** Refused, as above, and rightly so.

**Contradictory instructions.** `"Genre: death metal. Mood: soft and calming."` produces confusion, not creativity.

**Forgetting `Key`.** Naming a key gives the model a harmonic anchor, and you can hear it in the result.

## The model

Every successful submit carries `attribution: "Powered by MiniMax-Music3"`. That string is a licence obligation rather than a courtesy: it has to be visible wherever the song is, which is why the field is in the response instead of only in our documentation.

The full field reference for `POST /v1/music` — idempotency, polling, cancelling, and what a job response contains — is in the [API reference](https://docs.auray.ai/api-reference).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.auray.ai/documentation/prompting-music.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
