Generate a song

June 3, 2026 (November 9, 2026)

Table of contents

  1. Request Headers
  2. Request Body
  3. Responses
  4. Model
  5. Examples
  6. Try It

Generate a complete song from a text prompt using Lyria, on either lyria-3.5 (the current flagship) or lyria-3-pro (the default, see model below). Whether the result is vocal or instrumental is decided by the model from your prompt — describe vocals (or pass your own lyrics) to get a sung track with model-written lyrics, or set instrumental: true to force an instrumental. Each generation returns up to two clips (an A/B pair) and consumes credits from your account balance.

https://api.useapi.net/v1/flowmusic/music

Request Headers

Authorization: Bearer {API token}
Content-Type: application/json
# Alternatively you can use multipart/form-data
# Content-Type: multipart/form-data

Request Body

{
  "prompt": "lo-fi hip hop, mellow piano, 80 bpm",
  "instrumental": false,
  "ghostwriter": "pro"
}
  • email is optional. The Flow Music account to use. See GET /accounts for configured accounts. If not provided, the API automatically selects an account with available capacity. Specify when you want to use a specific configured account.
  • prompt is required, the song description — style, mood, genre, instruments, BPM, and any vocal direction. 1–10,000 characters.
  • instrumental is optional. true forces an instrumental (prepends an [Instrumental] tag). false (default) lets the model decide whether to sing based on your prompt.
  • lyrics is optional, your own lyrics, ideally [Verse]/[Chorus]-tagged (≤10,000 chars). Providing them forces a vocal render of those words. Omit them and the model writes lyrics only if the prompt implies vocals.
  • ghostwriter is optional, the lyrics-writer version used when the model writes the lyrics. It has no effect if you supply your own lyrics. Supported values: standard, pro.
  • model is optional, the music model used for the render. Supported values: lyria-3.5 and lyria-3-pro (default). lyria-3.5 is Google’s current flagship, described by Flow Music as its top-performing model with more dynamic vocals and richer musicality. lyria-3-pro is the older model every song generated through this API used before the parameter existed, so omitting model keeps your existing output unchanged.
  • refImage1 to refImage10 are optional, encoded image asset IDs from POST /files or POST /files/generate. Passed to the model only as uploaded-file hints (it may loosely nudge style) — not a literal reference.
  • refAudio1 to refAudio10 are optional, encoded audio asset IDs from POST /files. Experimental, limited effect — neither Lyria model truly references an uploaded song. The upload is passed only as a hint and may not influence the result.
  • mode is optional, sync (default) or async. In sync the request waits for the song, usually ~40–150 s, and returns 200 with the finished record (or the job’s error code). Only a song that is still not finished after 7 minutes returns 202 with the job in status: "pending" — fetch the result with GET /jobs/jobid or wait for the replyUrl webhook. The song keeps rendering on our side even if your connection drops, and it still lands in the job record and the webhook. async returns 201 immediately with a jobid, then you poll GET /jobs/jobid for the result. On platforms with short request timeouts, use async or replyUrl so you always have the jobid.
  • replyUrl is optional, webhook URL. When the job completes or fails the API POSTs the job record to it — the same shape as GET /jobs/jobid.
  • replyRef is optional, custom reference string echoed back in the webhook.

References must come from one account. A refImage/refAudio ID is tied to the account it was uploaded to, so if you pass any, they must all be from that one account — and the song is generated there. If you also pass email, it has to match, or the request fails with 400.

Responses

  • 200 OK

    Sync mode (default, or "mode": "sync") — the song is generated and the full record is returned inline. All audio lives in the clips[] array.

    {
      "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic",
      "email": "[email protected]",
      "status": "completed",
      "created_at": "2026-06-01T18:40:42.412Z",
      "completed_at": "2026-06-01T18:42:55.123Z",
      "duration_ms": 132711,
      "clips": [
        {
          "clip": "user:[email protected]:a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
          "title": "Morning Sun",
          "duration_s": 173.04,
          "lyrics": "[Verse 1]\nCity lights blur in the rain\n[Chorus]\nAnd I will wait for the morning sun",
          "seed": null,
          "lyrics_timing": [ [0.0, 2.4], [2.4, 5.1] ],
          "created_at": "2026-06-01T18:41:04.283Z",
          "audio_url": "https://storage.googleapis.com/...a1b2c3d4.m4a",
          "wav_url": "https://storage.googleapis.com/...a1b2c3d4.wav",
          "image_url": "https://storage.googleapis.com/...b2c3d4e5.jpg"
        }
      ],
      "request": { "prompt": "lo-fi hip hop, mellow piano, 80 bpm", "instrumental": false }
    }
    
  • 201 Created

    Async mode ("mode": "async") — the job is queued and returned immediately as pending. Poll GET /jobs/jobid until status is completed or failed.

    {
      "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic",
      "email": "[email protected]",
      "status": "pending",
      "created_at": "2026-06-01T18:40:42.412Z",
      "request": {
        "prompt": "upbeat funk groove, 110 bpm",
        "instrumental": true,
        "mode": "async"
      }
    }
    
  • 202 Accepted

    Sync mode only, and rare. The song was still not finished after 7 minutes, so the job is returned as it stands, pending. It keeps rendering: poll GET /jobs/jobid until status is completed or failed, or wait for the replyUrl webhook.

    {
      "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic",
      "email": "[email protected]",
      "status": "pending",
      "created_at": "2026-06-01T18:40:42.412Z",
      "request": {
        "prompt": "upbeat funk groove, 110 bpm",
        "instrumental": true
      }
    }
    
  • 400 Bad Request

    Validation error (missing/invalid parameter, or no account configured).

    {
      "error": "Parameter prompt is required",
      "code": 400
    }
    
  • 401 Unauthorized

    Invalid API token.

    {
      "error": "Unauthorized",
      "code": 401
    }
    
  • 402 Payment Required

    The targeted Flow Music account has insufficient credits to complete the generation. Top up its credit balance (or target a funded account with email), then retry.

    {
      "error": "FlowMusic conversation failed (402): {\"detail\":\"User has insufficient credits\"}",
      "code": 402
    }
    
  • 422

    The model produced no audio (e.g. a content-moderation refusal). A terminal job record with status: "failed".

    {
      "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic",
      "email": "[email protected]",
      "status": "failed",
      "created_at": "2026-06-01T18:40:42.412Z",
      "completed_at": "2026-06-01T18:41:10.512Z",
      "error": {
        "code": "moderation_reject",
        "message": "the model declined to generate audio for this prompt"
      },
      "request": { "prompt": "...", "instrumental": false }
    }
    
  • 429 Too Many Requests

    Returned in two cases.

    email omitted and every configured account is already at its maxJobs concurrency limit (load-balancing has nowhere to place the job) — retry once a running job finishes:

    {
      "error": "All 3 FlowMusic accounts are at their maxJobs concurrency limit — retry shortly",
      "code": 429
    }
    

    Or passed through from FlowMusic when a chosen account exceeds its own per-account limit (a single or email-targeted account running too many generations at once):

    {
      "error": "FlowMusic conversation failed (429): {\"detail\":\"Too Many Requests\"}",
      "code": 429
    }
    
  • 596 Account Error

    The account targeted by email is in an error state and can’t be used — re-add it via POST /accounts. The error field returns whatever reason was recorded for the account.

    {
      "error": "Account [email protected] in error state: refresh token rejected",
      "code": 596
    }
    

Model

  • {
      jobid: string                  // job:<uuid>-user:<id>-<email>-bot:flowmusic
      email: string
      status: 'completed' | 'pending' | 'failed'
      created_at: string             // ISO 8601 timestamp
      completed_at?: string          // present when terminal
      duration_ms?: number           // wall-clock generation time
      clips: Array<{
        clip: string                 // encoded clip asset id — use with /music/download and /music/edit
        title: string | null
        duration_s: number | null
        lyrics: string | null        // [Verse]/[Chorus]-tagged; "[Instrumental]" for instrumentals
        seed: number | null
        lyrics_timing: Array<[number, number]> | null  // timing markers, [start, end] seconds (vocal clips)
        created_at: string           // ISO 8601 timestamp
        audio_url: string            // signed m4a download URL
        wav_url: string              // signed wav download URL
        image_url: string | null     // auto-generated artwork URL
      }>
      request: {                     // the request body you submitted, echoed back verbatim
        prompt: string
        email?: string
        instrumental?: boolean
        lyrics?: string
        ghostwriter?: 'standard' | 'pro'
        model?: 'lyria-3.5' | 'lyria-3-pro'
        mode?: 'sync' | 'async'
        replyUrl?: string
        replyRef?: string
        refImage1?: string           // …up to refImage10 — encoded image asset IDs
        refAudio1?: string           // …up to refAudio10 — encoded audio asset IDs
      }
    }
    
  • {
      jobid: string                  // job:<uuid>-user:<id>-<email>-bot:flowmusic
      email: string
      status: 'pending'
      created_at: string             // ISO 8601 timestamp
      request: {                     // the request body you submitted, echoed back verbatim
        prompt: string
        email?: string
        instrumental?: boolean
        lyrics?: string
        ghostwriter?: 'standard' | 'pro'
        model?: 'lyria-3.5' | 'lyria-3-pro'
        mode?: 'sync' | 'async'
        replyUrl?: string
        replyRef?: string
        refImage1?: string           // …up to refImage10 — encoded image asset IDs
        refAudio1?: string           // …up to refAudio10 — encoded audio asset IDs
      }
    }
    

Examples

  • curl -H "Content-Type: application/json" \
         -H "Authorization: Bearer YOUR_API_TOKEN" \
         -X POST "https://api.useapi.net/v1/flowmusic/music" \
         -d '{ "prompt": "lo-fi hip hop, mellow piano, 80 bpm" }'
    
  • const response = await fetch('https://api.useapi.net/v1/flowmusic/music', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer YOUR_API_TOKEN',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        prompt: 'lo-fi hip hop, mellow piano, 80 bpm'
      })
    });
    const result = await response.json();
    console.log(result.clips?.[0]?.audio_url);
    
  • import requests
    
    response = requests.post(
        'https://api.useapi.net/v1/flowmusic/music',
        headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
        json={'prompt': 'lo-fi hip hop, mellow piano, 80 bpm'}
    )
    print(response.status_code, response.json())
    

Try It