Tutorials

Generate a Song with an AI API: From Prompt to MP3

TchaviBy Gael — Tchavi founder

· 8 min read

Back to blog

Table of contents

Generating a song through an API comes down to one call: POST /v1/music/generations, with a prompt and, if you want specific words, a lyrics field. The response isn't the audio file — it's a job, which finishes a minute or so later with an MP3 to fetch. This guide starts from an empty file and ends with a finished track: the exact code in cURL and Node.js, the two models available, what separates the prompt from the lyrics, the errors the API returns before charging you anything, and the real cost.

In short

  • POST /v1/music/generations is asynchronous: it answers 202 with a job id while the track renders in the background.
  • Two models: minimax-music-2.6 writes and performs a song from a description (329.242 credits, about KES 25 at October 2026 rates); minimax-music-cover re-sings a track you supply (658.484 credits, about KES 50). Billing is flat per track, up to five minutes, with no duration parameter.
  • The prompt carries musical direction — key, tempo, instruments, voice, mood. The lyrics carry the words — with [Verse] / [Chorus] markers. Mixing the two up gives a vaguer result.
  • You poll GET /v1/jobs/:id until completed or failed. A finished job answers with output.audio_url — not video_url, which belongs to the video endpoint.
  • Three combinations are refused with a 400, before any billing: a cover with no source_audio_url, a source_audio_url sent to a generator, and instrumental together with lyrics.
  • On our own runs, the song took 65.9 s to render for a 1:10 track; the cover took 76.4 s for a 1:06 track.

The first call: write a song

Create a key in your dashboard, then send a prompt:

curl -X POST https://tchavi.com/api/v1/music/generations \
  -H "Authorization: Bearer $TCHAVI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "minimax-music-2.6",
    "prompt": "Afrobeats mid-tempo, 100 BPM, key of C major, highlife guitar, round bass, warm female vocal, joyful reunion mood"
  }'

The response arrives right away, well before the track exists:

{
  "id": "0f3c1a2b-...",
  "object": "music.generation",
  "status": "pending",
  "model": "minimax-music-2.6",
  "created_at": "2026-11-05T09:12:03.000Z",
  "tchavi": {
    "credits_used": 329.242,
    "credits_remaining": 4821.5
  }
}

credits_used is charged on submission, not when the job finishes. If the job fails, that amount is refunded in full — there's nothing special your code has to do for that.

Polling the job to a finished file

The returned id is polled on the async jobs endpoint. A simple cURL loop:

JOB_ID="0f3c1a2b-..."

while true; do
  STATUS=$(curl -s https://tchavi.com/api/v1/jobs/$JOB_ID \
    -H "Authorization: Bearer $TCHAVI_API_KEY")
  echo "$STATUS" | grep -o '"status":"[a-z]*"'
  case "$STATUS" in
    *'"status":"completed"'*|*'"status":"failed"'*) break ;;
  esac
  sleep 5
done

echo "$STATUS"

A finished job answers with the file:

{
  "id": "0f3c1a2b-...",
  "status": "completed",
  "model": "minimax-music-2.6",
  "type": "MUSIC",
  "output": {
    "audio_url": "https://cdn.tchavi.com/.../track.mp3",
    "file_size_mb": 1.7,
    "url_expires_at": "2026-11-06T09:14:51.000Z"
  }
}

That's output.audio_url, not output.video_url — the latter belongs to video jobs, not music. output.url_expires_at is the deadline to download the file: past that, the signed link stops working.

With the Node.js SDK (coming soon)

The two cURL calls above are enough to write a song and fetch the file today — that's the path that works right now. The SDK, @tchavi/sdk, doesn't do this yet: client.music.generations is landing in a future release, not published yet. The snippet below shows what that will look like once the SDK ships it — don't install it expecting this to work today:

npm install @tchavi/sdk
import Tchavi from '@tchavi/sdk';

const client = new Tchavi({ apiKey: process.env.TCHAVI_API_KEY });

const submission = await client.music.generations.create({
  model: 'minimax-music-2.6',
  prompt:
    'Afrobeats mid-tempo, 100 BPM, key of C major, highlife guitar, round bass, warm female vocal',
});

console.log(submission.id, submission.tchavi.credits_used);

let job = await client.jobs.retrieve(submission.id);
while (job.status !== 'completed' && job.status !== 'failed') {
  await new Promise((r) => setTimeout(r, 5000));
  job = await client.jobs.retrieve(submission.id);
}

console.log(job.status, job.output?.audio_url);

Or, shorter, the helper that does both in one call (it waits up to 10 minutes by default, enough for a full song to render):

const job = await client.music.generations.createAndWait({
  model: 'minimax-music-2.6',
  prompt: 'Afrobeats mid-tempo, 100 BPM, highlife guitar, round bass, warm female vocal',
});

console.log(job.status, job.output?.audio_url);

Once shipped, the SDK should validate prompt and model before it even sends the request, and reject instrumental combined with lyrics locally, so you'd get the error immediately, without a round trip. Until then, both checks already happen server-side with the cURL calls shown above.

Here is what those two calls produce — a song written, sung and mixed by the model, from the prompt and lyrics below:

0:000:00

Prompt : A minor, 102 BPM, afrobeats with highlife guitar, round bass and log drum, female lead with a small backing choir, bright and hopeful, the energy of a market opening at dawn

minimax-music-2.6 · 329.242 credits · 1:10 · generated in 65.9 s

The prompt and the lyrics: two jobs, not one

This is the detail that changes the result the most: prompt and lyrics don't overlap.

The prompt describes the music itself: genre, tempo in BPM, key, instruments, voice type, mood. A prompt that only gives a mood — "a happy song about friendship" — leaves the model to guess the tempo and the key, and the result varies more from one call to the next. A prompt that states the tempo and the key gives something more predictable each time.

The lyrics carry the words and the structure of the track, with section markers:

[Verse]
We lost touch after you left Cotonou
Then ran into each other, out of the blue
[Chorus]
Come back, come back, the city kept you a seat
Come back, come back, nothing's really changed its beat

Leave out lyrics and minimax-music-2.6 writes its own from the prompt. Send instrumental: true for no vocals at all — but never together with lyrics: one asks for no voice, the other supplies words to sing, and the API refuses the contradiction before starting the job.

Covering an existing track: minimax-music-cover

minimax-music-cover keeps the melody of a track you supply and changes everything around it — genre, voice, instruments, arrangement. It requires source_audio_url, a publicly reachable MP3 or WAV:

curl -X POST https://tchavi.com/api/v1/music/generations \
  -H "Authorization: Bearer $TCHAVI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "minimax-music-cover",
    "prompt": "Soft acoustic version, female vocal, nylon-string guitar",
    "source_audio_url": "https://example.com/my-demo.mp3"
  }'

Twice the price of the model that writes a song from scratch: 658.484 credits, about KES 50, still a flat fee per track.

The cover below starts from the song you just heard, not from someone else's recording: same melody, acoustic arrangement.

0:000:00

Prompt : Gentle acoustic cover, nylon guitar and brushed percussion, warm female vocal, slower tempo, intimate studio feel

minimax-music-cover · 658.484 credits · 1:06 · generated in 76.4 s

Errors caught before billing

Three combinations are refused with a 400, before any credits are charged:

CaseResponse
minimax-music-cover with no source_audio_url400 bad_request — the model has nothing to re-sing
source_audio_url sent to minimax-music-2.6400 bad_request — a generator doesn't need one
instrumental: true with lyrics set400 bad_request — the two contradict each other
prompt or model missing400 bad_request (or rejected locally by the SDK)

None of these errors cost you a credit. If a job does start and fails later — on the model's side — the credits charged at submission are refunded in full; you see it in tchavi.credits_refunded on the job.

What it costs

KES figures are at October 2026 rates (about 13,204 credits per KES 1,000, so 1 credit is about KES 0.0757):

ModelWhat it doesCredits per trackPrice in KES
minimax-music-2.6Writes and performs a song, up to 5 minutes329.242about KES 25
minimax-music-coverRe-sings a track you supply, in a style you describe658.484about KES 50

That's a flat fee per track, not per second: a thirty-second song and a five-minute one cost the same. At that rate, a KES 250 top-up (about 3,300 credits) covers roughly 10 songs with minimax-music-2.6, or about 5 covers with minimax-music-cover.

The 50 credits granted at email verification don't cover a song: minimax-music-2.6 needs 329.242 at minimum. You'll need to top up your account before testing music — the cost of a try stays low, but it isn't free.

What we measured

Two runs, not a benchmark:

  • minimax-music-2.6: 65.9 seconds to render a 1:10 track.
  • minimax-music-cover: 76.4 seconds to render a 1:06 track.

Render time doesn't track the length of the output: both took around a minute, whether the result ran one minute or five.

How to try it

FAQ

Can you choose the length of the track?

No. There's no duration parameter: the model decides, up to five minutes, and the price doesn't change based on what it produces.

What happens if lyrics is present but empty?

Only send the field when you actually have words to give. An empty string isn't treated as "no lyrics."

Can music be tested with the free signup credits?

No. The 50 credits granted at email verification don't cover a track: minimax-music-2.6 needs 329.242. A top-up is required before your first try.

Can the job be polled indefinitely?

Yes, GET /v1/jobs/:id stays available after the job finishes, as long as the file hasn't expired. output.url_expires_at gives the deadline to download the MP3.

Does the SDK handle covers too?

Not yet on npm: client.music.generations is landing in a future SDK release. Until then, call POST /v1/music/generations directly with model: "minimax-music-cover" and a source_audio_url, as shown above.

create your account and top up KES 250

This article is part of the series "Building an AI product from Africa". Tchavi is an OpenAI-compatible AI API gateway: one key gives access to over 100 text, image, audio and video models, and you pay for it with mobile money, no bank card (countries and operators). More guides on the blog. Follow us: LinkedIn and X.

Share

Your first API call, paid with mobile money

No bank card. Top up with mobile money in your local currency; your first top-up adds 150 bonus credits, and credits never expire.