AI music generator API in Python: prompt to MP3 file
A short Python script that sends a prompt to Sume's Music Router, polls the job and saves the audio. Runs with httpx and asyncio.

To generate music from Python, POST a prompt to https://api.sume.com/v1/music-router/generate, poll the job's status_url until it is terminal, then read the audio artifact from the result and download it. The script below does that with httpx and asyncio and saves an MP3.
Request and job shapes are from the Music Router and Jobs and results docs, read 2026-09-29.
What is the script?
Set SUME_API_KEY first. The Idempotency-Key makes a retry of the same submit return the original job instead of billing a second one.
import asyncio
import os
import httpx
HEADERS = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
BODY = {
"prompt": "Warm lo-fi hip hop, 84 BPM, C minor. Dusty Rhodes, brushed drums. "
"A 30-second track. Instrumental, no vocals."
}
async def main() -> None:
async with httpx.AsyncClient(headers=HEADERS, timeout=60) as client:
r = await client.post(
"https://api.sume.com/v1/music-router/generate",
json=BODY,
headers={"Idempotency-Key": "music-py-001"},
)
r.raise_for_status()
job = r.json()["data"]
while not (s := (await client.get(job["status_url"])).json()["data"])["terminal"]:
await asyncio.sleep(s.get("next_poll_after_seconds") or 3)
if s["sume_status"] != "completed":
raise SystemExit(f"job ended as {s['sume_status']}")
res = (await client.get(job["result_url"])).json()["data"]["result"]
audio = next(a for a in res["artifacts"] if a["type"] == "audio")
open("track.mp3", "wb").write((await client.get(audio["url"])).content)
asyncio.run(main())What does each step read?
| Step | Detail |
|---|---|
| Submit | POST /v1/music-router/generate; default mode is async |
| Poll | status_url until terminal; honor next_poll_after_seconds |
| Result | result_url once result_ready; audio is in result.artifacts[], type audio |
| File | Typically audio/mpeg on media.sume.com |
What can go wrong?
- A non-empty
negative_promptor anydurationfield returns HTTP 400; leave both out. - Do not resubmit because your process timed out; poll the same job. Each new generation is billed.
- For waits you do not want to hold, use
mode: "webhook"with a public HTTPSwebhook_urland keep polling as a backup.
Sources
Related posts
More in Developers
- AI music negative prompt: why the API returns 400
Sume's music API rejects a non-empty negative_prompt with HTTP 400. What the error looks like and how to write exclusions in the prompt instead.
- AI music API webhook: get a callback when the track is ready
Submit a music job with mode webhook and a public HTTPS URL, verify the signed callback, and keep polling as a backup. Headers, events and retries.
- AI vendor risk assessment: questions and where to look
An AI vendor risk assessment adds training, model providers and spend to a SaaS review. The questions, and where Sume's public pages answer them.
- API sandbox environment: test a paid API without paying
An API sandbox is a separate test environment with fake or free results. Sume has none, so test with its spec, free checks and spend caps.
Written by Sume