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/generationsis asynchronous: it answers202with a jobidwhile the track renders in the background.- Two models:
minimax-music-2.6writes and performs a song from a description (329.242 credits, about KES 25 at October 2026 rates);minimax-music-coverre-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
promptcarries musical direction — key, tempo, instruments, voice, mood. Thelyricscarry the words — with[Verse]/[Chorus]markers. Mixing the two up gives a vaguer result. - You poll
GET /v1/jobs/:iduntilcompletedorfailed. A finished job answers withoutput.audio_url— notvideo_url, which belongs to the video endpoint. - Three combinations are refused with a
400, before any billing: a cover with nosource_audio_url, asource_audio_urlsent to a generator, andinstrumentaltogether withlyrics. - 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:
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.
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:
| Case | Response |
|---|---|
minimax-music-cover with no source_audio_url | 400 bad_request — the model has nothing to re-sing |
source_audio_url sent to minimax-music-2.6 | 400 bad_request — a generator doesn't need one |
instrumental: true with lyrics set | 400 bad_request — the two contradict each other |
prompt or model missing | 400 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):
| Model | What it does | Credits per track | Price in KES |
|---|---|---|---|
minimax-music-2.6 | Writes and performs a song, up to 5 minutes | 329.242 | about KES 25 |
minimax-music-cover | Re-sings a track you supply, in a style you describe | 658.484 | about 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
- Read the music generation docs and the async jobs docs.
- Both models have their own page with a demo:
minimax-music-2.6andminimax-music-cover. - The music catalogue lists both side by side.
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.