One endpoint, two modes.
Same request shape for songs and for instrumental tracks.
One endpoint, two modes
The API takes one request shape for instrumental tracks and for songs with vocals. Modes and voices are the only switch; there is no engine field to set and no engine name in any response.
POST https://glidingnote.ai/api/v1/generate
Authorization: Bearer gn_xxxxxxxx
Content-Type: application/json
{
"mode": "vocal", // "vocal" or "instrumental"
"genre": "acoustic pop", // free text, 80 characters max
"voice": "female", // female | male | humming | instrumental
"feel": "steady", // calm | steady | driving
"duration": 60, // 30 | 60 | 90 | 180
"lyrics": "[Verse]
...", // optional; vocal modes only
"loop": false
}
The response returns a job id and the credits charged. Poll the job until it is done or failed; a failed job is refunded.
202 {"ok": true, "id": "job_1a2b3c4d5e6f", "credits": 5, "status": "queued"}
GET https://glidingnote.ai/api/v1/jobs/job_1a2b3c4d5e6f
Authorization: Bearer gn_xxxxxxxx
200 {"ok": true, "id": "job_1a2b3c4d5e6f", "status": "done",
"audio": "/tracks/job_1a2b3c4d5e6f/job_1a2b3c4d5e6f-320.mp3",
"loop": null, "lyrics": "[Verse]
...", "error": null}
Minimal client
# Python
import json, time, urllib.request
KEY = "gn_xxxxxxxx"
def call(path, body=None):
req = urllib.request.Request("https://glidingnote.ai" + path,
data=json.dumps(body).encode() if body else None,
headers={"Authorization": "Bearer " + KEY, "Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=60) as r:
return json.loads(r.read())
job = call("/api/v1/generate", {"mode": "vocal", "genre": "acoustic pop", "voice": "female",
"feel": "steady", "duration": 60, "lyrics": "[Verse]
..."})
while True:
s = call("/api/v1/jobs/" + job["id"])
if s["status"] in ("done", "failed"):
break
time.sleep(5)
// JavaScript (Node 18+)
const KEY = "gn_xxxxxxxx";
const api = async (path, body) => {
const r = await fetch("https://glidingnote.ai" + path, {
method: body ? "POST" : "GET",
headers: { Authorization: "Bearer " + KEY, "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
return r.json();
};
const job = await api("/api/v1/generate", {
mode: "instrumental", genre: "lofi hip hop", feel: "steady", duration: 60, loop: true,
});
for (;;) {
const s = await api("/api/v1/jobs/" + job.id);
if (s.status === "done" || s.status === "failed") break;
await new Promise((r) => setTimeout(r, 5000));
}
Retries: generate is not idempotent, so retry only on 429 or 5xx and only when no job id came back. Poll with backoff (5 s, then 10 s); a failed job is refunded automatically. If lyrics are left out on a vocal mode, the take comes back wordless — there is no lyric writer.
Getting a key
Sign in with your Gliding Note account, then call POST /api/v1/keys. The key is shown once — store it on your server. Keys are per account and use the same credit balance as the website.
Fields
| Field | Type | Notes |
|---|---|---|
| mode | string | vocal or instrumental; defaults from voice |
| genre | string | free text style prompt, 80 characters max |
| voice | string | female, male, humming, instrumental |
| feel | string | calm, steady, driving |
| duration | number | 30, 60, 90 or 180 seconds |
| lyrics | string | optional: empty writes lyrics, a theme expands them, finished lyrics are used as-is. The job response returns the lyrics actually sung. |
| lyrics_exact | bool | true = use the lyrics exactly; incomplete lyrics return 422. false/omitted = incomplete lyrics are expanded. |
| loop | bool | adds a loopable version; costs the loop add-on. The job response then carries a loop URL. |
Limits and errors
Accepted jobs return 202 with Location and Retry-After. Send an Idempotency-Key header on generate to make a retry return the original job instead of a second charge. 30 requests a minute per key. 401 for a missing or revoked key, 402 when the balance is short, 429 when the limit is hit. A failed generation returns the credits automatically.
A finished track from $0.10
One credit balance. A single, a card, a journal or a campaign set. You hear it before you keep it.