Choose a model, enter your prompt, and see the result.
HiAPI Blog
HiAPI
Generate it with HiAPI
lyria-3.5 is hiapi's text-to-music model: send a musical description, lyrics, or both, and get back a finished audio track — with optional title, tempo guidance, and duration control. This guide walks through the full input schema, a request that returns a real track, and the production details you need past a one-off test.
sk-.curl or Python's requests. No SDK required; hiapi speaks plain REST.lyria-3.5 runs on hiapi's unified async task API: you POST a task, get a taskId back immediately, then either poll for the result or receive a callback when the track is ready.
lyria-3.5 accepts more than a bare prompt. Every field is optional except that you must supply at least one of prompt or lyrics:
| Field | Type | Notes |
|---|---|---|
prompt | string | Genre, instruments, mood, vocals, song structure. Provide prompt or lyrics. |
lyrics | string | One line per phrase. Section tags — [Intro], [Verse], [Chorus], [Bridge], [Outro] — each on their own line, followed by the lyrics. Number repeats as [Verse 1], [Verse 2]. |
title | string | Title of the generated song. |
bpm | string | Tempo guidance as a numeric string, e.g. "90". |
length | integer | Requested duration in seconds, 1–240. Guides length; actual duration may vary. Omit to leave unspecified. |
seed | string | Numeric string seed, e.g. "00123". Identical audio is not guaranteed even with the same seed. |
Two gotchas worth flagging up front: bpm and seed are strings, not numbers — send "90", not 90, or the API returns a 400 (got number, want string). And the schema is strict: any field not in the table above (duration, style, genre, negative_prompt, etc.) 400s with additional properties '...' not allowed.
curl -X POST "https://api.hiapi.ai/v1/tasks" \
-H "Authorization: Bearer sk-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "lyria-3.5",
"input": {
"prompt": "Warm instrumental indie folk, fingerpicked acoustic guitar, soft brushed drums, quiet morning",
"bpm": "90",
"length": 30
}
}'
A healthy response returns immediately, before the track is actually rendered:
{
"code": 200,
"message": "success",
"data": { "taskId": "tk-hiapi-01M2HCSKAP77MTH1ANKQXE1DT2" }
}
curl "https://api.hiapi.ai/v1/tasks/tk-hiapi-01M2HCSKAP77MTH1ANKQXE1DT2" \
-H "Authorization: Bearer sk-YOUR_API_KEY"
Wait a few seconds before the first poll, then check every 3–5 seconds. status moves through handling before landing on a terminal state. Here's the actual response for the request above, about 100 seconds later:
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01M2HCSKAP77MTH1ANKQXE1DT2",
"model": "lyria-3.5",
"status": "success",
"created": 1789437730,
"completed": 1789437829,
"output": [
{
"type": "audio",
"url": "https://temp.hiapi.ai/7c6ttvrbpt/01M2HCSKAP77MTH1ANKQXE1DT2-0.m4a",
"expireAt": 1790042629
}
]
}
}
Note the output container can vary by request (.m4a here; other music models on hiapi return .mp3) — read output[0].type/URL rather than hardcoding an extension. Download output[0].url promptly: the default temp storage tier expires around 7 days (expireAt is a Unix timestamp). On failure, status is fail and data.error holds { code, message } instead of output.
import time
import requests
API_KEY = "sk-YOUR_API_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
payload = {
"model": "lyria-3.5",
"input": {
"title": "Carry the Morning",
"lyrics": (
"[Verse 1]\n"
"Light through the window, coffee still warm\n"
"[Chorus]\n"
"Carry the morning, carry it slow\n"
),
"bpm": "96",
"length": 45,
},
}
create = requests.post("https://api.hiapi.ai/v1/tasks", headers=HEADERS, json=payload)
task_id = create.json()["data"]["taskId"]
status = None
while status not in ("success", "fail"):
time.sleep(4)
poll = requests.get(f"https://api.hiapi.ai/v1/tasks/{task_id}", headers=HEADERS).json()
status = poll["data"]["status"]
if status == "success":
print(poll["data"]["output"][0]["url"])
else:
print(poll["data"]["error"])
Swap lyrics for prompt (or send both) depending on whether you want an instrumental or a vocal track.
callback object: {"url": "https://yourapp.com/hook", "when": "final"}. when only accepts "final" — you get one call when the task reaches a terminal state, not progress updates.taskId as soon as you receive it, and check task status before firing a duplicate request on retry.error_code: "permission_denied". Schema violations return HTTP 400 with error_code: "INVALID_REQUEST" and a message naming the offending field — useful for catching a stray duration or numeric bpm before it reaches production.output[0].url to your own storage right after a successful poll or callback; don't rely on the temp tier past its expireAt.Do I need to send both prompt and lyrics? No — the API requires at least one of the two. Send prompt alone for an instrumental track, lyrics alone for a vocal track driven purely by the words, or both together.
What audio format does lyria-3.5 return? It varies by request — check output[0].type and the URL's extension rather than assuming .mp3 or .m4a.
Can I force an exact tempo? bpm is guidance, not a hard constraint, and it must be sent as a string ("90", not 90).
How long can a generated track be? length accepts 1–240 seconds, but it guides the model rather than guaranteeing an exact duration — check the actual runtime of the returned file.
Will the same seed give me the same track twice? No. seed is a numeric string that nudges generation, but hiapi's docs are explicit that identical audio isn't guaranteed.
What happens if I send an unrecognized field, like genre or duration? The schema is strict — you'll get a 400 with additional properties '<field>' not allowed instead of the field being silently ignored.