Python quickstart
Generate your first AI song from Python in about five minutes. The official Python SDK is on the roadmap — for now, the API is a plain JSON REST API and works cleanly with requests or httpx.
1. Get an API key
Sign in to the MusicAPI dashboard, open API Keys, and copy your key. New accounts get free credits to test with.
2. Install a HTTP client
Any modern Python HTTP library works. requests is the standard choice:
pip install requests
Or httpx if you want async support:
pip install httpx
3. Set the key in your environment
export MUSICAPI_KEY="your_key_here"
4. Check your credit balance
A one-call sanity check that confirms the key works:
import os
import requests
API_BASE = "https://api.musicapi.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['MUSICAPI_KEY']}"}
resp = requests.get(f"{API_BASE}/get-credits", headers=HEADERS, timeout=30)
resp.raise_for_status()
print(resp.json())
# → {"credits": 100, "extra_credits": 50}
5. Generate your first song
Submit a generation, then poll until it's ready:
import os
import time
import requests
API_BASE = "https://api.musicapi.ai/api/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['MUSICAPI_KEY']}",
"Content-Type": "application/json",
}
def generate_and_wait(payload: dict, poll_interval_s: float = 5.0, timeout_s: float = 300.0):
# Submit the generation.
submit = requests.post(f"{API_BASE}/sonic/create", json=payload, headers=HEADERS, timeout=60)
submit.raise_for_status()
task_id = submit.json()["task_id"]
# Poll. API returns HTTP 202 / {"type": "not_ready"} while running.
deadline = time.time() + timeout_s
while time.time() < deadline:
time.sleep(poll_interval_s)
poll = requests.get(f"{API_BASE}/sonic/task/{task_id}", headers=HEADERS, timeout=60)
if poll.status_code == 200:
return poll.json()
# 202 / not_ready / 102 = keep polling
raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")
result = generate_and_wait({
"custom_mode": False,
"mv": "sonic-v5",
"gpt_description_prompt": "uplifting synthwave with female vocals",
})
for song in result["data"]:
print(song["title"], song["audio_url"])
Two songs come back per generation — the model always returns a pair, and you can pick the one you like.
6. Drive it with custom lyrics + style tags
For full creative control, pass custom_mode: True and your own prompt (lyrics), title, and tags:
generate_and_wait({
"custom_mode": True,
"mv": "sonic-v5",
"prompt": "[Verse]\nCity lights, neon dreams\n[Chorus]\nDrive on, drive on…",
"title": "Night Drive",
"tags": "synthwave, retro, energetic",
})
7. Prefer webhooks over polling
Pass webhook_url (and optionally webhook_secret) in the create call and the API will POST the finished task to your URL. No polling, no idle compute.
requests.post(f"{API_BASE}/sonic/create", json={
"custom_mode": False,
"mv": "sonic-v5",
"gpt_description_prompt": "lofi hip hop for studying",
"webhook_url": "https://your-app.example.com/webhooks/musicapi",
"webhook_secret": "your-shared-secret",
}, headers=HEADERS, timeout=60)
8. Handle errors cleanly
The API uses standard HTTP semantics. Common failure modes:
| Status | Meaning | Action |
|---|---|---|
| 401 | API key invalid or missing | Check Authorization header |
| 402 | Insufficient credits / no subscription | Top up or upgrade |
| 429 | Rate limited | Back off; honor Retry-After header |
| 4xx (other) | Bad request | Check the response body for the specific field |
| 5xx | Server error | Retry with exponential backoff (the SDK does max 3 retries) |
If a job is submitted successfully but fails during generation (failed / timeout / forbidden / api_error in the task response), credits are automatically refunded by the API — no manual reconciliation needed.
A minimal retry helper:
import time
from requests.exceptions import HTTPError
def post_with_retry(url, *, json, max_retries=3):
for attempt in range(max_retries + 1):
resp = requests.post(url, json=json, headers=HEADERS, timeout=60)
if resp.status_code < 400:
return resp.json()
if resp.status_code in (429, 500, 502, 503, 504) and attempt < max_retries:
retry_after = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(retry_after)
continue
resp.raise_for_status()
What's next
- Generate music — full reference — every parameter, every response field, including extend/cover/concat task types.
- Aligned lyrics — per-word timing for karaoke-style display.
- Stems & WAV export — split vocals from instrumental, or get a lossless WAV.
- Playground — try a generation in the browser, no signup.