HookGenius API
Turn an idea into a finished title, full lyrics, and a producer-grade style prompt with one HTTP call — the same engine the HookGenius app runs on. Pair it with any audio generator (Suno, Udio, your own) for the sound.
Base URL https://api.hookgenius.app
Introduction
The API exposes a single capability: songwriting. You send an idea (plus any creative controls), and you get back a complete song spec — title, lyrics with section tags and vocal direction, and a style_prompt tuned to render correctly in a music model. Generation runs the full HookGenius pipeline (best-of-N drafting → critic selection → producer refinement), so it takes ~30–60 seconds per call. The API is therefore asynchronous: you create a job, then receive the result by polling, long-poll, or webhook.
Authentication
Authenticate every request with your secret API key as a bearer token. Keys come in two modes: hg_test_… (free sandbox) and hg_live_… (real generations, billed). Keys are shown once at creation and stored hashed — treat them like a password and never expose one in client-side code.
Authorization: Bearer hg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Quickstart
Create a generation and wait up to 60 seconds for the result inline using ?wait:
# 1 — create (and wait for) a generation curl https://api.hookgenius.app/v1/generations?wait=60 \ -H "Authorization: Bearer hg_live_…" \ -H "Content-Type: application/json" \ -d '{ "idea": "a triumphant late-night drive home after quitting a dead-end job", "genre": "synthwave", "vocal": { "gender": "male" } }'
# → 200 (completed within the wait window) { "id": "gen_8f2c…", "object": "generation", "status": "completed", "output": { "title": "Last Punch Out", "lyrics": "[Verse 1]\nBadge on the break room table…", "style_prompt": "synthwave outrun, 95 BPM, warm analog polysynth arpeggios, male warm baritone…", "languages": ["English"] }, "usage": { "credits": 1 } }
Then feed output.lyrics and output.style_prompt straight into your audio model's custom/lyrics mode.
Sandbox / test mode
A hg_test_ key returns a realistic sample response instantly — no real generation runs, and it never costs a credit. Use it to wire up auth, request shape, polling/webhooks, and error handling before you spend anything. Sandbox responses include "sandbox": true in the output and titles suffixed (sample) so you never confuse them with live output.
hg_live_ and the exact same code produces real songs.Create a generation
Creates a generation job. Returns 202 with a queued job immediately, or — if you pass ?wait=N and it finishes within N seconds (max 90) — 200 with the completed result. Billing is debit-before-generate: one credit is held when the job is created and automatically refunded if the generation fails. Test keys never charge.
Query parameters
| Param | Type | Description |
|---|---|---|
wait | integer | Optional. Long-poll up to N seconds (capped at 90) for the job to finish before responding. Omit to return 202 immediately and poll separately. |
Headers
| Header | Description |
|---|---|
Authorizationrequired | Bearer <key> |
Idempotency-Key | Optional. A unique string you generate; replaying the same key + body returns the original job instead of creating (or charging) a new one. See Idempotency. |
The async model
Because a generation takes ~30–60 seconds, choose one of three ways to receive the result:
1 · Long-poll (simplest)
POST /v1/generations?wait=60 # blocks up to 60s, # returns completed result
2 · Poll
POST /v1/generations → 202 {id} GET /v1/generations/{id} # repeat every ~3s until # status: completed
Retrieve a generation
Returns the current state of a generation. status is one of queued, processing, completed, or failed. Once completed, output is populated.
curl https://api.hookgenius.app/v1/generations/gen_8f2c… \
-H "Authorization: Bearer hg_live_…"
Request field reference
Every field below is accepted on POST /v1/generations and verified end-to-end against the live engine. Only idea is required; everything else sharpens the result.
| Field | Type | Description |
|---|---|---|
idearequired | string | The concept, theme, or brief for the song. Up to 2000 chars. |
genre | string | Primary genre, e.g. "synthwave", "arena rock", "folk". |
sub_genre | string | Refines the genre, e.g. "outrun". |
artist_influences | string[] | Artists to absorb the stylistic feel of. Influence is internalized, never named in the output. |
song_references | {title, artist}[] | Reference tracks to anchor the vibe. |
vocal | object | { "gender": "male" | "female" | "any", "description": "warm weary baritone" }. Both optional. |
languages | string[] | Languages to write in. Defaults to ["English"]. |
required_keywords | string[] | string | Words or phrases the lyrics must include. |
exclusions | string[] | Themes, words, or imagery to avoid (e.g. "religious imagery"). |
locked_lyrics | object | { "text": "…", "mode": "exact" | "enhance" | "inspire" }. Bring your own lyrics: exact preserves them verbatim and writes only the surrounding structure; enhance polishes them; inspire uses them as a seed. |
title | string | Optional fixed title. Omit to have one written for you. |
Response shape
{
"id": "gen_8f2c…",
"object": "generation",
"status": "completed", // queued | processing | completed | failed
"created_at": 1782851678, // unix seconds
"completed_at": 1782851731,
"output": {
"title": "…",
"lyrics": "…", // section tags + vocal direction included
"style_prompt": "…", // comma-separated, ready for a music model
"languages": ["English"]
},
"usage": { "credits": 1 },
"error": null
}
Usage & balance
Returns your remaining credit balance, mode, rate limit, calls in the last 60s, and recent generations.
{
"credits_remaining": 948,
"mode": "live",
"rate_limit_per_min": 30,
"used_last_60s": 2,
"recent": [ { "id": "gen_…", "status": "completed", "created_at": 1782851678 } ]
}
Key info
Returns metadata about the calling key, with the key value masked.
{ "id": "key_…", "key": "hg_live_…a1b2", "mode": "live", "credits_remaining": 948 }
Errors
Errors use standard HTTP status codes and a consistent JSON envelope:
{ "error": { "type": "insufficient_credits", "code": "no_credits", "message": "Insufficient credits. Top up your balance to continue." } }
| Status | type | When |
|---|---|---|
400 | invalid_request_error | Malformed JSON or invalid/missing fields (param names the field). |
401 | authentication_error | Missing or invalid API key. |
402 | insufficient_credits | Balance is zero. Top up to resume — no calls are charged while empty. |
403 | permission_error | Key revoked. |
404 | invalid_request_error | No generation with that id under your key. |
429 | rate_limit_error | Per-key rate limit exceeded. Respect the Retry-After header. |
Rate limits
Each key has a per-minute rate limit (default 30 requests/min; raised on request for higher-volume accounts). Exceeding it returns 429 with a Retry-After header. Generation latency, not the rate limit, is usually the throughput ceiling — design around the async model.
Idempotency
Safely retry create requests without risk of duplicate work or double-charging by sending a unique Idempotency-Key header. If we've already seen that key for your account, we return the original generation instead of creating a new one. Use a fresh UUID per logical generation.
curl https://api.hookgenius.app/v1/generations \ -H "Authorization: Bearer hg_live_…" \ -H "Idempotency-Key: 9f1c2e7a-…" \ -H "Content-Type: application/json" \ -d '{ "idea": "…" }'
Pricing & credits
One credit = one finished song. Credits are prepaid: buy them up front, and when your balance reaches zero the API pauses (returns 402) until you top up — no overage, no surprise bills.
| Tier | Price / generation |
|---|---|
| Standard | $0.99 |
| Volume — 1,000+ credits prepaid | $0.79 |
| Scale — 10,000+ credits prepaid | $0.69 |
| Sandbox / test mode | Free |
Failed generations are never charged. Manage credits and keys from your console.