=== useapi.net — universal note === Generated: 2026-10-14 19:29 UTC Authentication (applies to every useapi.net API). Header: Authorization: Bearer user:- Use the COMPLETE token, including the `user:` prefix and the alphanumeric suffix. Do not truncate. Do not URL-encode. A single token authorizes every API under the user's subscription. Service-specific patterns. Identifier names (jobid / taskId / musicId / etc.), job lifecycle, response shapes, webhook semantics, and synchronous-vs-async behavior vary PER API. Use ONLY the service-specific documentation below to determine the correct request body, response shape, polling endpoint, and status values for THIS API. Do not assume conventions from another useapi.net API carry over. For cross-service context (e.g. which APIs expose the same underlying model, billing tiers, model availability matrix), see https://useapi.net/llms.txt === END universal note === === URL: https://useapi.net/docs/start-here/setup-flowmusic === Document URL: https://useapi.net/docs/start-here/setup-flowmusic --- layout: default title: Setup Flow Music description: "How to set up FlowMusic for the useapi.net API — connect your account and start generating via the API." parent: Start Here nav_order: 208 permalink: /docs/start-here/setup-flowmusic --- # Setup Flow Music June 3, 2026 ## Table of contents Approximately 5 minutes to complete setup steps. --- > This is the setup guide for [Flow Music API](/docs/api-flowmusic-v1). A [Flow Music](https://www.flowmusic.app) account (Google sign-in) and a [useapi.net subscription](/docs/subscription) are required for the API to work. ### Automated setup (recommended) Use our guided browser setup to configure your account automatically — no DevTools or token copying needed. Enter your API token, sign in with Google in the remote browser, and your account is ready. [Open automated setup](/assets/setup-browser/flowmusic.html) Prefer manual setup? Continue with the steps below. --- [Flow Music](https://www.flowmusic.app) is [Google Labs](https://labs.google)' AI music generator, powered by the [Lyria 3 Pro](https://deepmind.google/models/lyria/) model (formerly Producer AI, originally [Riffusion](https://www.riffusion.com)). It creates complete, fully-produced songs — vocals, melody, and arrangement — from a text prompt, and can also cover/restyle songs, adjust lyrics in place, extend or replace sections, and apply audio effects. Flow Music signs you in with your Google account and keeps the session — including a **refresh token** — in your browser. To use the API you copy that refresh token and register it with [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts); useapi.net then calls Flow Music on your behalf and refreshes the token automatically. You can configure up to 50 Flow Music accounts per single [useapi.net subscription](/docs/subscription). ### Sign in to Flow Music * Navigate to [https://www.flowmusic.app](https://www.flowmusic.app) * Sign in with your Google account. We **strongly recommend** using a dedicated Google account for the API — not your personal Gmail. * Generate at least one song, and upload at least one image **and** one audio file. Doing each once in the browser dismisses Flow Music's first-use consent dialogs. ### Copy your refresh token 1. Open [https://www.flowmusic.app](https://www.flowmusic.app) `1` and make sure you're **signed out** (sign out if you're already signed in). 2. Open browser DevTools (**F12**) and select the **Network** tab `2`. 3. Click **Login** `3` and sign in with Google — this triggers a fresh token exchange. (The screenshot shows that button as **New session** because it changes to that once sign-in completes.) 4. In the Network filter box, type `sb.flowmusic.app/auth/v1/token` `4`. 5. Click the `token?grant_type=pkce` request that appears `5`. 6. Open the **Response** tab and copy the value of `refresh_token` `6`. ![](/assets/images/flowmusic-setup-1.jpg) ⚠️ **Important — manual setup only:** once the account is added to the API, **clear Flow Music's cookies** in your browser (or just close it and stop using Flow Music there). **Do not sign out** — signing out revokes the refresh token and disables the API account. Also don't keep browsing Flow Music there, or it will refresh the token itself and rotate it away from the API. Let the API fully manage the session from here on. The [automated setup](#automated-setup-recommended) handles all of this for you — it captures the token in a throwaway remote browser with no lingering session, so it's strongly preferred. If an account later stops working, repeat these steps and re-run [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). ### Verify and add account Paste your API token and the `refresh_token` below to register the account — you should receive a `201` (new) or `200` (updated) response. You can also call [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts) directly.
=== URL: https://useapi.net/docs/api-flowmusic-v1/delete-flowmusic-accounts-email === Document URL: https://useapi.net/docs/api-flowmusic-v1/delete-flowmusic-accounts-email --- layout: default title: DELETE accounts/`email` description: "Remove a configured Flow Music account by email via DELETE accounts/email in the useapi.net FlowMusic API v1 — unlinks the refresh token and frees the account slot." parent: FlowMusic API v1 nav_order: 140 permalink: /docs/api-flowmusic-v1/delete-flowmusic-accounts-email --- ## Remove an account June 3, 2026 --- Remove a configured Flow Music account from your useapi.net account. > **https://api.useapi.net/v1/flowmusic/accounts/`email`** - `email` is URL-encoded in the path. ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Responses **204** **204 No Content** — the account was deleted. The response body is empty. **401** **401 Unauthorized** — invalid API token. **404** **404** — account not configured. ### Examples **Curl** ``` bash curl -X DELETE -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/accounts/user@email.com" ``` **Python** ``` python import requests, urllib.parse email = 'user@email.com' r = requests.delete('https://api.useapi.net/v1/flowmusic/accounts/' + urllib.parse.quote(email, safe=''), headers={'Authorization': 'Bearer YOUR_API_TOKEN'}) print(r.status_code) # 204 No Content (empty body) ``` ### Try It
=== URL: https://useapi.net/docs/api-flowmusic-v1/delete-flowmusic-jobs-jobid === Document URL: https://useapi.net/docs/api-flowmusic-v1/delete-flowmusic-jobs-jobid --- layout: default title: DELETE jobs/`jobid` description: "Cancel a running async job and free its concurrency slot via DELETE jobs/jobid in the useapi.net FlowMusic API v1 — marks the record as failed with user_cancelled." parent: FlowMusic API v1 nav_order: 420 permalink: /docs/api-flowmusic-v1/delete-flowmusic-jobs-jobid --- ## Cancel a job June 3, 2026 --- Cancel a running async job and free its concurrency slot. The job record is marked `failed` with error code `user_cancelled` (terminal records are simply removed from the running set). > **https://api.useapi.net/v1/flowmusic/jobs/`jobid`** - `jobid` is URL-encoded in the path. ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Responses **204** **204 No Content** — cancelled (or slot already freed). No body. **401** **401 Unauthorized** — invalid API token. **403** **403** — the jobid does not belong to your account. **404** **404** — no job with that id. ### Model A successful cancel returns `204 No Content` with no body. Only the error responses (`403` / `404`) carry a JSON `{ error, code }`. ### Examples **Curl** ``` bash JOBID="job:56ef7890-...-bot:flowmusic" curl -X DELETE -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/jobs/$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$JOBID")" ``` **Python** ``` python import requests, urllib.parse jobid = 'job:56ef7890-...-bot:flowmusic' r = requests.delete('https://api.useapi.net/v1/flowmusic/jobs/' + urllib.parse.quote(jobid, safe=''), headers={'Authorization': 'Bearer YOUR_API_TOKEN'}) print(r.status_code) # 204 ``` ### Try It
=== URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-accounts-email === Document URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-accounts-email --- layout: default title: GET accounts/`email` description: "Retrieve a configured Flow Music account's details by email via GET accounts/email in the useapi.net FlowMusic API v1, including token state and concurrency settings." parent: FlowMusic API v1 nav_order: 120 permalink: /docs/api-flowmusic-v1/get-flowmusic-accounts-email --- ## Get one account June 3, 2026 --- Get the detail for a single configured account. > **https://api.useapi.net/v1/flowmusic/accounts/`email`** - `email` is the account's email address (URL-encoded in the path). ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Responses **200** **200 OK** ```json { "email": "user@email.com", "tier": "plus", "subscription_plan": "plus-monthly", "provider": "g1_entitlement", "user_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "maxJobs": 12, "added": "2026-06-01T12:00:00.000Z", "refreshed_at": "2026-06-01T12:00:00.000Z", "refreshed_count": 0, "access_token": "eyJ…redacted…zmQ", "access_token_expires_at": "2026-06-01T13:00:00.000Z", "refresh_token": "l6e…redacted…z4v", "session_id": "f0e1d2c3-b4a5-4768-9a0b-1c2d3e4f5a6b", "credits_remaining": 5000, "tokens_remaining": 60000 } ``` - `credits_remaining` and `tokens_remaining` are live-pulled from Flow Music on every request, so they are always current. They are returned only for a healthy account — an account in an error state (`error` present) omits them because its balance can't be queried. **401** **401 Unauthorized** — invalid API token. **404** **404** — account not configured. ### Model ```typescript { email: string tier: 'free' | 'starter' | 'plus' | 'member' | 'unknown' subscription_plan?: string // paid tiers only provider?: string // paid tiers only user_id: string // the account's user UUID maxJobs: number added: string // ISO 8601 timestamp refreshed_at: string // ISO 8601 timestamp refreshed_count: number access_token: string // redacted access_token_expires_at: string // ISO 8601 timestamp refresh_token: string // redacted session_id: string error?: string // present only when the account needs re-authentication credits_remaining?: number | null // live-pulled per request; present only for a healthy account tokens_remaining?: number | null // live-pulled per request; present only for a healthy account } ``` ### Examples **Curl** ``` bash curl -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/accounts/user@email.com" ``` **Python** ``` python import requests, urllib.parse email = 'user@email.com' r = requests.get('https://api.useapi.net/v1/flowmusic/accounts/' + urllib.parse.quote(email, safe=''), headers={'Authorization': 'Bearer YOUR_API_TOKEN'}) print(r.status_code, r.json()) ``` ### Try It
=== URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-accounts-usage === Document URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-accounts-usage --- layout: default title: GET accounts/usage description: "Retrieve credit and token usage for a Flow Music account via GET accounts/usage in the useapi.net FlowMusic API v1 — daily billing events and per-song cost summaries." parent: FlowMusic API v1 nav_order: 130 permalink: /docs/api-flowmusic-v1/get-flowmusic-accounts-usage --- ## Account usage June 3, 2026 --- Token and credit usage for an account — raw billing events plus per-type and per-song summaries, aggregated per UTC day. > **https://api.useapi.net/v1/flowmusic/accounts/usage?email=`email`** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Query Parameters - `email` (required) is which configured account to report on. ### Responses **200** **200 OK** ```json { "email": "user@email.com", "events": [ { "type": "producer-usage", "amount": 60, "conversation_id": "11112222-3333-4444-8555-666677778888", "conversation_title": "Sample Song", "event_at": "2026-06-01T00:00:00", "max_created_at": "2026-06-01T18:42:55.123456Z", "_account_email": "user@email.com" } ], "summary": { "by_type_tokens": { "daily-free": 1440, "riffusion": 60, "producer-usage": 1200, "grant": 7200 }, "by_type_credits": { "daily-free": 120, "riffusion": 5, "producer-usage": 100, "grant": 600 }, "total_charged_credits": 105, "total_received_tokens": 8640, "per_conversation": [ { "conversation_id": "11112222-3333-4444-8555-666677778888", "title": "Sample Song", "email": "user@email.com", "tokens": 60, "credits": 5 } ] } } ``` - `events` lists per-day usage rows, aggregated per UTC day. Each row carries a `type`, an `amount` in tokens, the `conversation_id` / `conversation_title` it belongs to, `event_at` (start of the UTC day), and `max_created_at` (the latest actual event time in that day). - `summary.by_type_tokens` and `by_type_credits` total the amounts per event type (credits are tokens / 12). - `total_charged_credits` sums the charged types (`producer-usage`, `riffusion`). `total_received_tokens` sums grants and free allowances. - `per_conversation` breaks the spend down per song. See [Flow Music pricing](https://www.flowmusic.app/pricing?plan=yearly) for plan allowances and per-generation costs. **401** **401 Unauthorized** — invalid API token. **404** **404** — account not configured. ### Model ```typescript { email: string events: Array<{ type: string // e.g. 'producer-usage' | 'riffusion' | 'daily-free' | 'grant' amount: number // tokens conversation_id: string | null conversation_title: string | null event_at: string // start of the UTC day this row is bucketed into max_created_at: string // latest actual event time in that day _account_email: string }> summary: { by_type_tokens: Record by_type_credits: Record // tokens / 12 total_charged_credits: number total_received_tokens: number per_conversation: Array<{ conversation_id: string title: string | null email: string | null tokens: number credits: number }> } } ``` ### Examples **Curl** ``` bash curl -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/accounts/usage?email=user@email.com" ``` **Python** ``` python import requests r = requests.get('https://api.useapi.net/v1/flowmusic/accounts/usage', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}, params={'email': 'user@email.com'}) print(r.status_code, r.json()) ``` ### Try It
=== URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-accounts === Document URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-accounts --- layout: default title: GET accounts description: "List all Flow Music accounts configured under your useapi.net account via GET accounts in the useapi.net FlowMusic API v1 — email, tier, maxJobs, token state, and re-auth error flag." parent: FlowMusic API v1 nav_order: 110 permalink: /docs/api-flowmusic-v1/get-flowmusic-accounts --- ## List accounts June 3, 2026 --- List all Flow Music accounts configured under your useapi.net account. > **https://api.useapi.net/v1/flowmusic/accounts** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Responses **200** **200 OK** ```json { "user@email.com": { "email": "user@email.com", "tier": "plus", "subscription_plan": "plus-monthly", "provider": "g1_entitlement", "user_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "maxJobs": 12, "added": "2026-06-01T12:00:00.000Z", "refreshed_at": "2026-06-01T12:00:00.000Z", "refreshed_count": 0, "access_token": "eyJ…redacted…zmQ", "access_token_expires_at": "2026-06-01T13:00:00.000Z", "refresh_token": "l6e…redacted…z4v", "session_id": "f0e1d2c3-b4a5-4768-9a0b-1c2d3e4f5a6b" } } ``` - The response is an object keyed by account email (`{}` when no accounts are configured). - `error` is present only when an account needs re-authentication (re-run [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts)) — healthy accounts omit it. - Credit balances are omitted from the list — fetch them live per account via [GET /accounts/`email`](/docs/api-flowmusic-v1/get-flowmusic-accounts-email). **401** **401 Unauthorized** — invalid API token. ### Model An object keyed by account email (`{}` when none are configured). ```typescript { [email: string]: { email: string tier: 'free' | 'starter' | 'plus' | 'member' | 'unknown' subscription_plan?: string // paid tiers only provider?: string // paid tiers only user_id: string // the account's user UUID maxJobs: number added: string // ISO 8601 timestamp refreshed_at: string // ISO 8601 timestamp refreshed_count: number access_token: string // redacted access_token_expires_at: string // ISO 8601 timestamp refresh_token: string // redacted session_id: string error?: string // present only when the account needs re-authentication } } ``` ### Examples **Curl** ``` bash curl -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/accounts" ``` **Python** ``` python import requests r = requests.get('https://api.useapi.net/v1/flowmusic/accounts', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}) print(r.status_code, r.json()) ``` ### Try It
=== URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-jobs-jobid === Document URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-jobs-jobid --- layout: default title: GET jobs/`jobid` description: "Poll an async generation by jobid via GET jobs/jobid in the useapi.net FlowMusic API v1 — returns status, clips on completion, and error details on failure." parent: FlowMusic API v1 nav_order: 410 permalink: /docs/api-flowmusic-v1/get-flowmusic-jobs-jobid --- ## Poll a job June 3, 2026 --- Fetch one job record by its `jobid`. Use this to poll an [async](/docs/api-flowmusic-v1/post-flowmusic-music) generation until `status` is `completed` or `failed`. > **https://api.useapi.net/v1/flowmusic/jobs/`jobid`** - `jobid` is URL-encoded in the path (it contains `:` and `@`). ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Responses **200** **200 OK** ```json { "jobid": "job:56ef7890-...-bot:flowmusic", "email": "user@email.com", "request": { "prompt": "...", "mode": "async" }, "created_at": "2026-05-31T19:57:23.954Z", "completed_at": "2026-05-31T19:59:43.118Z", "duration_ms": 139164, "status": "completed", "clips": [ { "clip": "user:1234-...-clip:...", "duration_s": 173.03, "image_url": "..." } ] } ``` While still running, only `status: "pending"` and the dispatch fields are present (no `clips`). **401** **401 Unauthorized** — invalid API token. **403** **403** — the jobid does not belong to your account. **404** **404** — no job with that id (expired or never existed). ### Model The job record — the same shape returned by [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music) and [POST /music/edit](/docs/api-flowmusic-v1/post-flowmusic-music-edit). `operation` is present only for edit jobs, `clips` appears once `completed`, and `error` appears when `failed`. ```typescript { jobid: string // job:-user:--bot:flowmusic email: string operation?: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' // edit jobs only 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<{ // present once completed clip: string // encoded clip asset id — use with /music/download and /music/edit title: string | null duration_s: number | null lyrics: string | null seed: number | null lyrics_timing: Array<[number, number]> | null // timing markers, [start, end] seconds (vocal clips) created_at: string audio_url: string wav_url: string image_url: string | null }> error?: { // present when status is 'failed' code: string message: string } request: object // the original request body, echoed back verbatim } ``` ### Examples **Curl** ``` bash JOBID="job:56ef7890-...-bot:flowmusic" curl -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/jobs/$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$JOBID")" ``` **Python** ``` python import requests, urllib.parse jobid = 'job:56ef7890-...-bot:flowmusic' r = requests.get('https://api.useapi.net/v1/flowmusic/jobs/' + urllib.parse.quote(jobid, safe=''), headers={'Authorization': 'Bearer YOUR_API_TOKEN'}) print(r.status_code, r.json()) ``` ### Try It
=== URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-jobs === Document URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-jobs --- layout: default title: GET jobs description: "List all currently-running async jobs grouped by account via GET jobs in the useapi.net FlowMusic API v1 — shows running counts and maxJobs concurrency limits." parent: FlowMusic API v1 nav_order: 400 permalink: /docs/api-flowmusic-v1/get-flowmusic-jobs --- ## List running jobs June 3, 2026 --- List the currently-running async jobs, grouped by account email. Useful for tracking concurrency against each account's `maxJobs` limit. > **https://api.useapi.net/v1/flowmusic/jobs** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Responses **200** **200 OK** ```json { "user@email.com": { "running": 1, "maxJobs": 12, "jobs": [ { "jobid": "job:56ef7890-...-bot:flowmusic", "status": "pending", "created_at": "2026-05-31T19:57:23.954Z" } ] } } ``` An empty object `{}` means nothing is running. **401** **401 Unauthorized** — invalid API token. ### Model An object keyed by account email (`{}` when nothing is running). ```typescript { [email: string]: { running: number maxJobs: number jobs: Array<{ jobid: string status: 'pending' | 'completed' | 'failed' operation?: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' // edit jobs only created_at: string // ISO 8601 timestamp }> } } ``` ### Examples **Curl** ``` bash curl -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/jobs" ``` **Python** ``` python import requests r = requests.get('https://api.useapi.net/v1/flowmusic/jobs', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}) print(r.status_code, r.json()) ``` ### Try It
=== URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-music-download === Document URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-music-download --- layout: default title: GET music/download description: "Download a generated clip as raw mp3 audio bytes via GET music/download in the useapi.net FlowMusic API v1 — pass a clip ID, receive the binary stream directly." parent: FlowMusic API v1 nav_order: 240 permalink: /docs/api-flowmusic-v1/get-flowmusic-music-download --- ## Download raw mp3 audio June 3, 2026 --- Download a generated clip as raw `mp3` audio — the response body is the audio bytes. The full-quality **m4a** and **wav** are public URLs already on every clip, so they aren't re-served here: read `audio_url` / `wav_url` from [GET /music](/docs/api-flowmusic-v1/get-flowmusic-music) (or the job record) and download those directly. > **https://api.useapi.net/v1/flowmusic/music/download** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Query Parameters - `id` is **required**, an encoded clip asset ID (`user:--clip:`) or a completed jobid (resolves to the job's first clip). - `format` is optional, `mp3` (the default and only value). > **Stems are separate clips.** When you separate a song's stems in Flow Music it creates one clip per track — they show up in [GET /music](/docs/api-flowmusic-v1/get-flowmusic-music) as `" - drums"`, `"- bass"`, `"- vocals"`, `"- other"`. Download each one here with its own `id` (or grab its `audio_url`/`wav_url`). ### Responses **200** **200 OK** — the raw `audio/mpeg` bytes, with a `Content-Disposition` filename (`<clip>.mp3`). **400** **400** — `id` is not a valid clip ID or jobid, or `format` is unsupported. ```json { "error": "Parameter id not a valid clip ID or jobid", "code": 400 } ``` **401** **401 Unauthorized** — invalid API token. **409** **409** — a jobid was given but the job is not completed yet. **596** **596 Account Error** The account that owns the requested clip is in an error state and can't be used — re-add it via [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). The `error` field returns whatever reason was recorded for the account. ```json { "error": "Account user@email.com in error state: refresh token rejected", "code": 596 } ``` ### Model This endpoint streams raw `audio/mpeg` bytes (not JSON), with a `Content-Disposition` filename. Only the error responses (`400` / `409`) return JSON `{ error, code }`. ### Examples **Curl** ``` bash # Any clip — including a separated stem clip — downloads as mp3 by its id curl -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/music/download?id=user:1234-user@email.com-clip:12ab34cd-...&format=mp3" \ --output song.mp3 ``` **Python** ``` python import requests, urllib.parse clip = 'user:1234-user@email.com-clip:12ab34cd-...' url = 'https://api.useapi.net/v1/flowmusic/music/download?id=' + urllib.parse.quote(clip) + '&format=mp3' r = requests.get(url, headers={'Authorization': 'Bearer YOUR_API_TOKEN'}) open('song.mp3', 'wb').write(r.content) ``` ### Try It This endpoint returns raw audio bytes (not JSON), so the form below fetches the file with your token and plays it inline. <script> async function apiTestDownloadFlowMusic() { const id = document.getElementById('get-music-download-FlowMusic-id')?.value; const data = { method: 'GET', headers: { 'Authorization': `Bearer ${document.getElementById('get-music-download-FlowMusic-token').value}` } }; const url = `https://api.useapi.net/v1/flowmusic/music/download?id=${encodeURIComponent(id)}&format=mp3`; await apiExecute(url, 'get-music-download-FlowMusic', data, { expectMedia: true }); } </script> <form id="get-music-download-FlowMusic" onsubmit="return false;" class="input-form"> <div class="input-field"> <div class="input-field-row"> <label for="get-music-download-FlowMusic-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="get-music-download-FlowMusic-token" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="get-music-download-FlowMusic-id"><span>id<small> (encoded clip id or jobid)</small></span> <input id="get-music-download-FlowMusic-id" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> </div> <button id="get-music-download-FlowMusic-button" class="btn btn-primary fs-3" type="submit" onclick="apiTestDownloadFlowMusic()">Go</button> </div> </form> <div id="get-music-download-FlowMusic-response" class="response-placeholder visible-false"></div> === URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-music === Document URL: https://useapi.net/docs/api-flowmusic-v1/get-flowmusic-music --- layout: default title: <code class="language-plaintext highlighter-rouge background-method-get">GET</code> music description: "List generated clips on a Flow Music account via GET music in the useapi.net FlowMusic API v1 — paginated, most recent first, with clip IDs, titles, lyrics, and cover image URLs." parent: FlowMusic API v1 nav_order: 230 permalink: /docs/api-flowmusic-v1/get-flowmusic-music --- ## List clips <small>June 3, 2026</small> --- List the clips generated on a Flow Music account, most recent first. Paginated by `offset`. > **https://api.useapi.net/v1/flowmusic/music** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Query Parameters - `email` is optional, which configured account to list. Defaults to an available account. - `limit` is optional, the page size, 1–100 (default 20). - `offset` is optional, the page offset, ≥ 0 (default 0). ### Responses **200** **200 OK** ```json { "email": "user@email.com", "clips": [ { "clip": "user:1234-user@email.com-clip:12ab34cd-...", "title": "Morning Sun", "lyrics": "[Verse 1]\n...", "duration_s": 173.03, "image_url": "https://storage.googleapis.com/..." } ], "limit": 20, "offset": 0, "next": 20 } ``` - `next` is the `offset` to request for the following page, or `null` when this was the last page. **401** **401 Unauthorized** — invalid API token. **596** **596 Account Error** The account targeted by `email` is in an error state and can't be used — re-add it via [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). The `error` field returns whatever reason was recorded for the account. ```json { "error": "Account user@email.com in error state: refresh token rejected", "code": 596 } ``` ### Model ```typescript { email: string clips: Array<{ clip: string // encoded clip asset id — use with /music/download and /music/edit title: string | null lyrics: string | null duration_s: number | null image_url: string | null }> limit: number offset: number next: number | null // offset for the next page, or null when this was the last page } ``` ### Examples **Curl** ``` bash curl -H "Authorization: Bearer YOUR_API_TOKEN" \ "https://api.useapi.net/v1/flowmusic/music?limit=10&offset=0" ``` **Python** ``` python import requests response = requests.get( 'https://api.useapi.net/v1/flowmusic/music', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}, params={'limit': 10, 'offset': 0} ) print(response.status_code, response.json()) ``` ### Try It <script> async function apiTestGetMusicFlowMusic() { const data = { method: 'GET', headers: { 'Authorization': `Bearer ${document.getElementById('get-music-FlowMusic-token').value}` } }; let email = document.getElementById(`get-music-FlowMusic-email`)?.value; let limit = document.getElementById(`get-music-FlowMusic-limit`)?.value; let offset = document.getElementById(`get-music-FlowMusic-offset`)?.value; const qs = new URLSearchParams(); if (email) qs.set('email', email); if (limit) qs.set('limit', limit); if (offset) qs.set('offset', offset); const url = `https://api.useapi.net/v1/flowmusic/music` + (qs.toString() ? `?${qs.toString()}` : ''); await apiExecute(url, 'get-music-FlowMusic', data); } </script> <form id="get-music-FlowMusic" onsubmit="return false;" class="input-form"> <div class="input-field"> <div class="input-field-row"> <label for="get-music-FlowMusic-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="get-music-FlowMusic-token" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="get-music-FlowMusic-email"><span>email<small> (optional)</small></span> <input id="get-music-FlowMusic-email" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="get-music-FlowMusic-limit"><span>limit<small> (optional, 1-100)</small></span> <input id="get-music-FlowMusic-limit" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="get-music-FlowMusic-offset"><span>offset<small> (optional, >=0)</small></span> <input id="get-music-FlowMusic-offset" type="text" class="input-element" oninput="this.size = this.value.length"> </label> </div> <button id="get-music-FlowMusic-button" class="btn btn-primary fs-3" type="submit" onclick="apiTestGetMusicFlowMusic()">Go</button> </div> </form> <div id="get-music-FlowMusic-response" class="response-placeholder visible-false"></div> === URL: https://useapi.net/docs/api-flowmusic-v1 === Document URL: https://useapi.net/docs/api-flowmusic-v1 --- layout: default title: FlowMusic API v1 description: "useapi.net Flow Music API v1 — REST API for Google Flow Music by Google Labs, powered by the Lyria 3.5 and Lyria 3 Pro models (formerly Producer AI, originally Riffusion): generate full songs from a prompt, plus cover, remix, extend and stems." nav_order: 2100 has_children: true permalink: /docs/api-flowmusic-v1 --- # <img style="height:1em;vertical-align: middle;" src="/assets/images/google-flow-music-logo.jpg"> FlowMusic API v1 <small>June 3, 2026 (October 7, 2026)</small> <img src="/assets/images/disclaimer/disclaimer-google.svg" alt="" style="max-width:100%;display:block;margin:6px 0 4px;box-shadow:none;border-radius:0"> This is the [experimental](/docs/legal) API for [Google Flow Music](https://www.flowmusic.app) by [Google Labs](https://labs.google), powered by the [Lyria](https://deepmind.google/models/lyria/) music models. Flow Music was formerly Producer AI, and originally [Riffusion](https://www.riffusion.com). Two models are available through the `model` parameter on [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music) and [POST /music/edit](/docs/api-flowmusic-v1/post-flowmusic-music-edit) — `lyria-3.5`, the current flagship, and `lyria-3-pro`, which stays the default so existing integrations keep rendering exactly what they rendered before. [Flow Music](https://www.flowmusic.app) turns a text prompt, mood, or lyric idea into a complete, fully-produced song up to ~3 mins long (5+ with `extend`) — vocals, melody, and arrangement — using [Lyria](https://deepmind.google/models/lyria/). It also covers (restyles) existing songs, adjusts lyrics in place, extends or replaces sections, and applies audio effects. Each generation returns up to two clips (an A/B pair). Sign in to [flowmusic.app](https://www.flowmusic.app) with your Google account. See the [Flow Music pricing page](https://www.flowmusic.app/pricing) for plans and credit allowances. A song costs about $0.008–$0.013 on paid plans (see the cost calculator below for details), vs $0.08 per song on Google's [official Lyria 3 Pro API](https://cloud.google.com/gemini-enterprise-agent-platform/generative-ai/pricing#lyria). Roughly 6–10× cheaper, and includes cover, remix, extend/replace, effects, and stem-splitting. Downloads (mp3, wav, m4a, and stems) are free. <details markdown="block"> <summary><b>💲 Cost calculator</b></summary> Each generation costs ~5 to 10 credits and returns one or two songs (5 credits per song). All plans include daily top-up credits, so even Free generates a little each day. Max concurrent is how many generations the API runs at once per account (the `maxJobs` cap). | Plan | Price <br>month | Credits <br>month | ~Songs <br>month | ~Cost / song | Max concurrent | |---|---|---|---|---|---| | Free | $0 | daily top-up only | — | free daily credits | 2 | | Starter <br>monthly | $8 | 3,000 | ~600 | ~$0.013 | 8 | | Plus <br>monthly | $24 | 10,000 | ~2,000 | ~$0.012 | 12 | | Member <br>monthly | $64 | 30,000 | ~6,000 | ~$0.011 | 16 | | Starter <br>yearly | $6 | 3,000 | ~600 | ~$0.010 | 8 | | Plus <br>yearly | $18 | 10,000 | ~2,000 | ~$0.009 | 12 | | Member <br>yearly | $48 | 30,000 | ~6,000 | ~$0.008 | 16 | Yearly rows show the per-month price when billed annually (~25% off). </details> #### One Google account, four APIs The same Google AI plan powers several useapi.net APIs, each from its own allowance, so one Google account connected to all of them gets the most out of the plan: - [Google Flow API](/docs/api-google-flow-v1): Veo 3.1 and Omni 1.1 Flash video, Nano Banana images up to 4K, from Flow credits. - [Google Vids API](/docs/api-google-vids-v1): Omni 1.1 Flash video with avatars and voices, from the Vids allowance, which does not use Flow credits. - [NotebookLM API (Gemini Notebook API)](/docs/api-gemini-notebook-v1): chat with sources, Deep Research and every Studio output, from the Gemini Notebook usage limits. - [FlowMusic API](/docs/api-flowmusic-v1): full songs with Lyria in Google Flow Music, which signs in with a Google account too, on Flow Music's own plans. Each API is set up on its own setup page, and one useapi.net subscription covers all of them. You can configure up to 50 Flow Music accounts per single [useapi.net account](/docs/subscription). ⚙️ [Setup Flow Music](/docs/start-here/setup-flowmusic) 💻 [GitHub examples](https://github.com/useapi/flowmusic-api) <small>Node.js: full songs with Lyria 3.5 and Lyria 3 Pro</small> 📦 [Postman collection](https://www.postman.com/useapinet/useapi-net/collection) 🤖 [LLM-friendly API spec](https://useapi.net/assets/aibot/api-flowmusic-v1.txt) <small>Feed this to your LLM to build integrations</small> Articles: * [How to Generate AI Music with Lyria 3 Pro via the Flow Music API](/docs/articles/flowmusic-bash) * [AI Music APIs Compared: Mureka vs MiniMax vs ElevenLabs vs Lyria 3 Pro](/docs/articles/ai-music-api-comparison) * [Four AI Music APIs on the Same Six Briefs: TemPolor v4.8, MiniMax Music-3.0, Lyria 3.5 and Mureka V9.5](/docs/articles/ai-music-flagships-compared) Examples: * [Generate songs with Google's Lyria 3.5](/blog/260812) * [Generate and edit songs with FlowMusic API](/blog/260603) Developer Community: * <a href="https://discord.gg/w28uK3cnmF"><img style="height:1em;vertical-align: middle;" src="/assets/images/discord.svg"> Discord Server</a> * <a href="https://t.me/use_api"><img style="height:1.3em;vertical-align: middle;" src="/assets/images/telegram.svg"> Telegram Channel</a> === URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-accounts === Document URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-accounts --- layout: default title: <code class="language-plaintext highlighter-rouge background-method-post">POST</code> accounts description: "Add or refresh a Flow Music account via POST accounts in the useapi.net FlowMusic API v1 — provide a refresh token to add access, or update maxJobs on an existing account by email." parent: FlowMusic API v1 nav_order: 100 permalink: /docs/api-flowmusic-v1/post-flowmusic-accounts --- ## Configure a Flow Music account <small>June 3, 2026</small> --- Configure a [Flow Music](https://www.flowmusic.app) account for API access using its refresh token. See [Setup Flow Music](/docs/start-here/setup-flowmusic) for how to obtain the token. You can configure up to 50 Flow Music accounts per single [useapi.net account](/docs/subscription). To change an account's concurrency limit later, re-POST with just `email` + `maxJobs` (no token) — see **Request Body** below. > **https://api.useapi.net/v1/flowmusic/accounts** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Request Body **Add or refresh an account** — provide the `refresh_token`: ```json { "refresh_token": "bdykxtrr5eaf...", "maxJobs": 12 } ``` - `refresh_token` is **required** to add or refresh, the flowmusic.app refresh token (≥10 chars). See [Setup Flow Music](/docs/start-here/setup-flowmusic). - `maxJobs` is optional, the max concurrent jobs for this account, 1–16 (defaults to the plan tier). **Update `maxJobs` on an existing account** — provide `email` + `maxJobs`, with no `refresh_token`: ```json { "email": "user@email.com", "maxJobs": 4 } ``` - `email` is **required** for this mode — an already-configured account. - `maxJobs` is **required** here, 1–16. Only this field is updated; no token refresh happens. Send nothing else alongside `email`. ### Responses **200** **200 OK** — existing account updated. ```json { "email": "user@email.com", "tier": "plus", "subscription_plan": "plus-monthly", "provider": "g1_entitlement", "user_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "maxJobs": 12, "added": "2026-06-01T12:00:00.000Z", "refreshed_at": "2026-06-01T12:00:00.000Z", "refreshed_count": 0, "access_token": "eyJ…redacted…zmQ", "access_token_expires_at": "2026-06-01T13:00:00.000Z", "refresh_token": "l6e…redacted…z4v", "session_id": "f0e1d2c3-b4a5-4768-9a0b-1c2d3e4f5a6b" } ``` - Credit balances are not included here — fetch them live from [GET /accounts/`email`](/docs/api-flowmusic-v1/get-flowmusic-accounts-email). **201** **201 Created** — new account configured. Same body as `200`. **400** **400** — add mode: missing/invalid `refresh_token`, or the token failed to refresh. Update mode: `maxJobs` missing or outside 1–16, or `email` sent together with `refresh_token`. ```json { "error": "maxJobs is required when updating an account by email", "code": 400 } ``` **404** **404** — update mode: no account is configured for the given `email`. ```json { "error": "Account user@email.com not found", "code": 404 } ``` **401** **401 Unauthorized** — invalid API token. ### Model `200` (updated) and `201` (created) return the same account record. ```typescript { email: string tier: 'free' | 'starter' | 'plus' | 'member' | 'unknown' subscription_plan?: string // paid tiers only provider?: string // paid tiers only user_id: string // the account's user UUID maxJobs: number added: string // ISO 8601 timestamp refreshed_at: string // ISO 8601 timestamp refreshed_count: number access_token: string // redacted access_token_expires_at: string // ISO 8601 timestamp refresh_token: string // redacted session_id: string error?: string // present only when the account needs re-authentication } ``` ### Examples **Curl** ``` bash curl -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -X POST "https://api.useapi.net/v1/flowmusic/accounts" \ -d '{ "refresh_token": "bdykxtrr5eaf...", "maxJobs": 12 }' ``` **Python** ``` python import requests response = requests.post( 'https://api.useapi.net/v1/flowmusic/accounts', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}, json={'refresh_token': 'bdykxtrr5eaf...', 'maxJobs': 12} ) print(response.status_code, response.json()) ``` ### Try It <script> async function apiTestPostAccountsFlowMusic() { const refresh_token = document.getElementById('post-accounts-FlowMusic-refresh_token')?.value; const email = document.getElementById('post-accounts-FlowMusic-email')?.value; const maxJobs = document.getElementById('post-accounts-FlowMusic-maxJobs')?.value; const payload = {}; if (refresh_token) payload.refresh_token = refresh_token; if (email) payload.email = email; if (maxJobs) payload.maxJobs = parseInt(maxJobs); const data = { method: 'POST', headers: { 'Authorization': `Bearer ${document.getElementById('post-accounts-FlowMusic-token').value}`, 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }; await apiExecute(`https://api.useapi.net/v1/flowmusic/accounts`, 'post-accounts-FlowMusic', data); } </script> <form id="post-accounts-FlowMusic" onsubmit="return false;" class="input-form"> <div class="input-field"> <div class="input-field-row"> <label for="post-accounts-FlowMusic-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="post-accounts-FlowMusic-token" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="post-accounts-FlowMusic-refresh_token"><span>refresh_token<small> (add mode — see <a href="/docs/start-here/setup-flowmusic">Setup Flow Music</a>)</small></span> <input id="post-accounts-FlowMusic-refresh_token" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-accounts-FlowMusic-email"><span>email<small> (update mode — existing account)</small></span> <input id="post-accounts-FlowMusic-email" type="text" class="input-element" placeholder="user@email.com"> </label> <label for="post-accounts-FlowMusic-maxJobs"><span>maxJobs<small> (optional to add / required to update, 1–16)</small></span> <input id="post-accounts-FlowMusic-maxJobs" type="number" class="input-element" min="1" max="16" oninput="this.size = this.value.length"> </label> </div> <button id="post-accounts-FlowMusic-button" class="btn btn-primary fs-3" type="submit" onclick="apiTestPostAccountsFlowMusic()">Go</button> </div> </form> <div id="post-accounts-FlowMusic-response" class="response-placeholder visible-false"></div> === URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-files-generate === Document URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-files-generate --- layout: default title: <code class="language-plaintext highlighter-rouge background-method-post">POST</code> files/generate description: "Generate an AI image from a prompt via POST files/generate in the useapi.net FlowMusic API v1 — returns a refImage asset ID for use as a style reference in song generation." parent: FlowMusic API v1 nav_order: 310 permalink: /docs/api-flowmusic-v1/post-flowmusic-files-generate --- ## Generate an AI image <small>June 3, 2026</small> --- Generate an AI image from a text prompt. Returns an encoded image asset ID — the same shape [POST /files](/docs/api-flowmusic-v1/post-flowmusic-files) returns for an uploaded image — that you can pass as a reference image (`refImage1…`) to [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music). > **https://api.useapi.net/v1/flowmusic/files/generate** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Request Body ```json { "prompt": "abstract neon city skyline at night" } ``` - `email` is optional, which configured account to use. - `prompt` is **required**, the image description. 1–2,000 characters. ### Responses **200** **200 OK** ```json { "id": "user:1234-user@email.com-image:...", "url": "https://storage.googleapis.com/producer-app-public/assets/....jpg", "kind": "image", "assetType": "image", "email": "user@email.com", "width": 1024, "height": 1024, "model": "google-generative-ai" } ``` **400** **400** — missing/empty prompt. **401** **401 Unauthorized** — invalid API token. **500** **500** — Flow Music declined the request. The most common cause is a moderated or otherwise disallowed prompt: Flow Music returns a generic `Internal Server Error` (it does not say why) and we pass it through verbatim. Retry with a different prompt — if a clearly benign prompt still fails, it is likely a transient upstream error. ```json { "error": "FlowMusic image generation failed (500): \"Internal Server Error\"", "code": 500 } ``` **596** **596 Account Error** The account targeted by `email` is in an error state and can't be used — re-add it via [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). The `error` field returns whatever reason was recorded for the account. ```json { "error": "Account user@email.com in error state: refresh token rejected", "code": 596 } ``` ### Model ```typescript { id: string // encoded image asset id — usable as refImage1… in POST /music url: string kind: 'image' assetType: 'image' email: string width: number height: number model: string // the image model, e.g. 'google-generative-ai' } ``` ### Examples **Curl** ``` bash curl -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -X POST "https://api.useapi.net/v1/flowmusic/files/generate" \ -d '{ "prompt": "abstract neon city skyline at night" }' ``` **Python** ``` python import requests response = requests.post( 'https://api.useapi.net/v1/flowmusic/files/generate', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}, json={'prompt': 'abstract neon city skyline at night'} ) print(response.status_code, response.json()) ``` ### Try It <script> function displayFlowMusicImage(response, elementId) { const container = document.getElementById(`${elementId}-media-links`); if (!container) return; container.innerHTML = ''; if (!response.url) { container.style.display = 'none'; return; } const u = response.url; container.innerHTML = `<div style="margin:6px 0;"><a href="${u}" target="_blank" rel="noopener noreferrer" title="Open full image in a new tab"><img src="${u}" alt="generated image" style="max-width:256px;border-radius:6px;cursor:zoom-in;"></a></div>`; container.style.display = 'block'; } async function apiTestFilesGenerateFlowMusic() { const elementId = 'post-files-generate-FlowMusic'; const data = { method: 'POST', headers: { 'Authorization': `Bearer ${document.getElementById('post-files-generate-FlowMusic-token').value}`, 'Content-Type': 'application/json' } }; let email = document.getElementById(`post-files-generate-FlowMusic-email`)?.value; let prompt = document.getElementById(`post-files-generate-FlowMusic-prompt`)?.value; const url = `https://api.useapi.net/v1/flowmusic/files/generate`; data.body = JSON.stringify({ ...(email ? { email } : {}), prompt }); const mediaLinks = document.getElementById(`${elementId}-media-links`); if (mediaLinks) mediaLinks.style.display = 'none'; const status = await apiExecute(url, elementId, data, { includeTimer: true }); if (status === 200) { try { const response = JSON.parse(document.getElementById(`${elementId}-response-json`).innerText); displayFlowMusicImage(response, elementId); } catch (e) { console.error('Failed to parse response for image display:', e); } } } </script> <form id="post-files-generate-FlowMusic" onsubmit="return false;" class="input-form"> <div class="input-field"> <div class="input-field-row"> <label for="post-files-generate-FlowMusic-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="post-files-generate-FlowMusic-token" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="post-files-generate-FlowMusic-email"><span>email<small> (optional)</small></span> <input id="post-files-generate-FlowMusic-email" type="text" class="input-element" placeholder="user@email.com"> </label> <label for="post-files-generate-FlowMusic-prompt"><span>prompt</span> <textarea id="post-files-generate-FlowMusic-prompt" class="input-element" rows="3" required aria-required="true" style="resize: both;"></textarea> </label> </div> <button id="post-files-generate-FlowMusic-button" class="btn btn-primary fs-3" type="submit" onclick="apiTestFilesGenerateFlowMusic()">Go</button> </div> </form> <div id="post-files-generate-FlowMusic-media-links" style="display:none;"></div> <div id="post-files-generate-FlowMusic-response" class="response-placeholder visible-false"></div> === URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-files === Document URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-files --- layout: default title: <code class="language-plaintext highlighter-rouge background-method-post">POST</code> files description: "Upload a reference image or audio file via POST files in the useapi.net FlowMusic API v1 — returns an asset ID for use as refImage/refAudio in song generation." parent: FlowMusic API v1 nav_order: 300 permalink: /docs/api-flowmusic-v1/post-flowmusic-files --- ## Upload a file <small>June 3, 2026</small> --- Upload a reference image or audio file. The file is sent as the **raw request body**, with its MIME type in the `Content-Type` header (no multipart, no form fields). Returns an encoded asset ID you can pass to [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music) (`refImage1…`/`refAudio1…`). > **https://api.useapi.net/v1/flowmusic/files** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: {file MIME type} # see supported types below ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. The request body **is** the file's raw bytes. | Content-Type | File Extension | Max size | | ------------ | -------------- | -------- | | image/jpeg | jpg | 20 MB | | image/png | png | 20 MB | | image/webp | webp | 20 MB | | audio/mpeg | mp3 | 40 MB | | audio/wav | wav | 40 MB | | audio/mp4 | m4a | 40 MB | | audio/x-m4a | m4a | 40 MB | | audio/aac | m4a | 40 MB | ### Query Parameters - `email` is optional, which configured account to use. - `stripMetadata` is optional, default `true` — strips AI-provenance / EXIF metadata from images before upload (Flow Music's edge rejects images that declare AI-generated provenance). Set `false` to keep the original bytes. ### Responses **200** **200 OK** ```json { "id": "user:1234-user@email.com-image:34cd56ef-...", "url": "https://storage.googleapis.com/...", "kind": "image", "assetType": "image", "email": "user@email.com", "metadata_stripped": true } ``` Audio uploads also include `clip_id`, `operation_id`, `is_flagged`, and `duration_s` when available. **400** **400** — unsupported Content-Type, empty body, or magic-byte mismatch (declared type ≠ actual bytes). ```json { "error": "Content-Type (application/octet-stream) not supported. Valid values: image/jpeg, image/png, ...", "code": 400 } ``` **401** **401 Unauthorized** — invalid API token. **413** **413** — file exceeds the size cap. **422** **422** — image declares AI-generated provenance metadata and `stripMetadata=false` was set. Remove the flag (default strips it) or re-save the image without metadata. **500** **500** — FlowMusic rejected the upload or hit an internal error. Image moderation (e.g. NSFW) surfaces here as a `flowmusic_error`. The `upstream` block preserves the evidence — quote `cf_ray` to support. ```json { "error": "Upload failed (HTTP 500): FlowMusic: \"Internal Server Error\"", "code": 500, "upstream": { "status": 500, "cause": "flowmusic_error", "cf_ray": "a05b815ef02cf9cc-SJC", "server": "cloudflare", "content_type": "application/json" } } ``` **596** **596 Account Error** The account targeted by `email` is in an error state and can't be used — re-add it via [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). The `error` field returns whatever reason was recorded for the account. ```json { "error": "Account user@email.com in error state: refresh token rejected", "code": 596 } ``` ### Model ```typescript { id: string // encoded asset id — user:<id>-<email>-<image|audio>:<uuid> url: string // Flow Music storage URL kind: 'image' | 'audio' assetType: 'image' | 'audio' email: string metadata_stripped?: boolean // images only — whether AI-provenance metadata was stripped clip_id?: string | null // audio only operation_id?: string | null // audio only is_flagged?: boolean | null // audio only duration_s?: number | null // audio only } ``` ### Examples **Curl** ``` bash curl -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: image/png" \ -X POST "https://api.useapi.net/v1/flowmusic/files" \ --data-binary "@image.png" ``` **JavaScript** ``` javascript const bytes = await (await fetch('image.png')).arrayBuffer(); const response = await fetch('https://api.useapi.net/v1/flowmusic/files', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_TOKEN', 'Content-Type': 'image/png' }, body: bytes }); console.log(await response.json()); ``` **Python** ``` python import requests data = open('image.png', 'rb').read() response = requests.post( 'https://api.useapi.net/v1/flowmusic/files', headers={'Authorization': 'Bearer YOUR_API_TOKEN', 'Content-Type': 'image/png'}, data=data ) print(response.status_code, response.json()) ``` ### Try It <script> async function apiTestFilesFlowMusic() { const responseEl = document.getElementById('post-files-FlowMusic-response'); const file = document.getElementById('post-files-FlowMusic-file')?.files?.[0]; if (!file) { responseEl.classList.remove('visible-false'); responseEl.classList.add('visible-true'); responseEl.innerHTML = '<div class="response-status http-status-bad">Choose a file first</div>'; return; } const email = document.getElementById('post-files-FlowMusic-email')?.value; const stripMetadata = document.getElementById('post-files-FlowMusic-stripMetadata')?.value; const qs = new URLSearchParams(); if (email) qs.set('email', email); if (stripMetadata) qs.set('stripMetadata', stripMetadata); const url = `https://api.useapi.net/v1/flowmusic/files` + (qs.toString() ? `?${qs.toString()}` : ''); const data = { method: 'POST', headers: { 'Authorization': `Bearer ${document.getElementById('post-files-FlowMusic-token').value}`, 'Content-Type': file.type }, body: file }; await apiExecute(url, 'post-files-FlowMusic', data); } </script> <form id="post-files-FlowMusic" onsubmit="return false;" class="input-form"> <div class="input-field"> <div class="input-field-row"> <label for="post-files-FlowMusic-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="post-files-FlowMusic-token" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="post-files-FlowMusic-email"><span>email<small> (optional)</small></span> <input id="post-files-FlowMusic-email" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-files-FlowMusic-stripMetadata"><span>stripMetadata<small> (optional)</small></span> <select id="post-files-FlowMusic-stripMetadata" class="input-element"> <option value="">default (true)</option> <option value="false">false — keep original bytes</option> </select> </label> <label for="post-files-FlowMusic-file"><span>file<small> (image or audio)</small></span> <input id="post-files-FlowMusic-file" type="file" class="input-element" accept="image/jpeg,image/png,image/webp,audio/mpeg,audio/wav,audio/mp4,audio/aac" required aria-required="true"> </label> </div> <button id="post-files-FlowMusic-button" class="btn btn-primary fs-3" type="submit" onclick="apiTestFilesFlowMusic()">Go</button> </div> </form> <div id="post-files-FlowMusic-response" class="response-placeholder visible-false"></div> === URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music-edit === Document URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music-edit --- layout: default title: <code class="language-plaintext highlighter-rouge background-method-post">POST</code> music/edit description: "Edit a generated clip via POST music/edit in the useapi.net FlowMusic API v1 — cover, remix, extend, replace, apply audio effects, or separate into stems." parent: FlowMusic API v1 nav_order: 210 permalink: /docs/api-flowmusic-v1/post-flowmusic-music-edit --- ## Edit a song <small>June 3, 2026 (August 12, 2026)</small> --- Edit an existing clip — the `operation` field selects one of six edit kinds, each taking a `clip` (an encoded clip asset ID from a previous generation or [GET /music](/docs/api-flowmusic-v1/get-flowmusic-music)). `operation` is **required** — one of: | `operation` | What it does | Required params | Optional params | | ----------- | ------------ | --------------- | --------------- | | `effect` | Apply one audio effect | `effect` + that effect's scalar param(s) | — | | `extend` | Add new music to the end, or from a point | `instruction` | `extend_s`, `extend_from_s` | | `replace` | Regenerate a time section | `instruction`, `mask_start_s`, `mask_end_s` | — | | `cover` | Restyle the whole song (a Lyria cover) | — | `instruction`, `strength`, `model` | | `remix` | Re-sing with edited lyrics | `lyrics` | `prompt` | | `stems` | Separate into 4 stem clips (drums/bass/vocals/other) | — | — | > **https://api.useapi.net/v1/flowmusic/music/edit** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Request Body Every operation accepts these common fields (there is no `email` — the `clip` already identifies its account, and the edit runs there): - `clip` is **required**, the encoded clip asset ID to edit. - `seed` is optional, an integer ≥ 0 — pins the result for reproducibility. - `title` is optional, a title for the result clip. - `model` is optional, the music model used to re-render. Supported values: `lyria-3.5` and `lyria-3-pro` (default). It is sent with the operations that re-synthesise audio — `cover`, `extend`, `replace`, and `remix`. `effect` and `stems` accept it but their output is unaffected, because those are signal processing and stem separation with no music model in the loop. Omitting it keeps the behaviour that existed before the parameter was added. - `mode` is optional, `sync` (default — blocks until ready) or `async` (returns `201` with a `jobid`; poll [GET /jobs/`jobid`](/docs/api-flowmusic-v1/get-flowmusic-jobs-jobid)). In `sync` your connection must stay open until ready — if it drops the result is lost, so prefer `async` on mobile, flaky networks, or short-timeout platforms. Ignored by `stems`, which is always sync. - `replyUrl` is optional, a webhook URL — the job record is POSTed to it when the edit completes or fails. Ignored by `stems`. - `replyRef` is optional, a custom reference string echoed back in the webhook. Plus the chosen operation's own fields, below. #### operation: `effect` `effect` is one of `Trim`, `Fade`, `Gain`, `Reverb`, `Pan`, `Equalizer`. Each effect reads only its own flat scalar params (sending a param for a different effect is ignored): - `Gain` — `gain_db` (−30 … 30). - `Reverb` — `mix`, `room_size` (0 … 1 each). - `Pan` — `pan` (−1 left … 1 right). - `Equalizer` — `bass_db`, `mid_db`, `treble_db` (−12 … 12 each). - `Fade` — `fade_in_s`, `fade_out_s` (≥ 0, at least one > 0). - `Trim` — `start_s`, `end_s` (`end_s` > `start_s`, ≤ duration). ```json { "operation": "effect", "clip": "user:1234-user@email.com-clip:...", "effect": "Reverb", "mix": 0.4, "room_size": 0.7 } ``` #### operation: `extend` ```json { "operation": "extend", "clip": "user:1234-...-clip:...", "instruction": "add an instrumental outro", "extend_s": 30 } ``` - `instruction` is **required**, what to add. - `extend_s` is optional, seconds to add, 1–300 (default 150). - `extend_from_s` is optional, the point to extend from (default = end of clip). #### operation: `replace` ```json { "operation": "replace", "clip": "user:1234-...-clip:...", "instruction": "softer piano in this section", "mask_start_s": 0, "mask_end_s": 8 } ``` - `instruction` is **required**, how to regenerate the section. - `mask_start_s` is **required**, the section start (seconds). - `mask_end_s` is **required**, the section end (seconds), > `mask_start_s`, ≤ duration. #### operation: `cover` Restyle the entire song. `instruction` is **optional** (a free-text style direction); `strength` is the cover-strength slider. ```json { "operation": "cover", "clip": "user:1234-...-clip:...", "instruction": "lo-fi chillhop reinterpretation", "strength": 0.7 } ``` - `instruction` is optional, a free-text style direction. - `strength` is optional, 0 … 1 (default 1). #### operation: `remix` Re-sing the song with **edited lyrics**. By default it reuses the source song's sound prompt; override with `prompt`. The edited lyrics round-trip into the result clip's `lyrics`. ```json { "operation": "remix", "clip": "user:1234-...-clip:...", "lyrics": "[Verse 1]\nNeon rain on the avenue\n[Chorus]\nWe rise again", "prompt": "dreamy synthwave, 100 bpm" } ``` - `lyrics` is **required**, the edited lyrics, `[Verse]`/`[Chorus]`-tagged. - `prompt` is optional, a sound-prompt override (defaults to the source clip's). #### operation: `stems` Separate the song into its individual tracks. Flow Music runs the split server-side and creates **4 new clips** — `drums`, `bass`, `vocals`, `other` — each a normal clip with its own id and a public `audio_url`/`wav_url`. Only `clip` is needed. ```json { "operation": "stems", "clip": "user:1234-...-clip:..." } ``` - `stems` is **synchronous** — the request blocks ~15–60 s while the split runs, then returns all four stems in one reply (it ignores `mode`/`replyUrl`/`replyRef`). Re-running on an already-split clip returns its stems immediately. - Download any stem with [GET /music/download](/docs/api-flowmusic-v1/get-flowmusic-music-download) (mp3) or its `audio_url`/`wav_url`. Its response differs from the other edits — it's a flat manifest of the stem clips, not a job record: ```json { "email": "user@email.com", "operation": "stems", "source_clip": "user:1234-...-clip:...", "status": "completed", "clips": [ { "stem_type": "drums", "clip": "user:1234-...-clip:...", "title": "Song - drums", "duration_s": 173.0, "audio_url": "https://storage.googleapis.com/...1a2b3c4d.m4a", "wav_url": "https://storage.googleapis.com/...1a2b3c4d.wav", "image_url": null } ] } ``` (four entries — `drums`, `bass`, `vocals`, `other`). ### Responses Same job-record shape as [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music) — `operation` echoes the requested edit kind. (`operation: stems` is the exception — it returns the flat stem manifest shown above, not a job record.) **200** **200 OK** **Sync mode** (default) — the edit is rendered and the full record is returned inline. ```json { "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:1234-user@email.com-bot:flowmusic", "email": "user@email.com", "operation": "cover", "status": "completed", "created_at": "2026-06-01T18:40:42.412Z", "completed_at": "2026-06-01T18:41:37.432Z", "duration_ms": 55020, "clips": [ { "clip": "user:1234-user@email.com-clip:c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f", "title": "Morning Sun (Cover)", "duration_s": 171.02, "lyrics": "[Verse 1]\nCity lights blur in the rain\n[Chorus]\nAnd I will wait for the morning sun", "seed": 123456, "lyrics_timing": [ [0.0, 2.4], [2.4, 5.1] ], "created_at": "2026-06-01T18:41:30.118Z", "audio_url": "https://storage.googleapis.com/...c3d4e5f6.m4a", "wav_url": "https://storage.googleapis.com/...c3d4e5f6.wav", "image_url": "https://storage.googleapis.com/...d4e5f6a7.jpg" } ], "request": { "operation": "cover", "clip": "user:1234-user@email.com-clip:...", "strength": 0.7 } } ``` **201** **201 Created** **Async mode** (`"mode": "async"`) — the edit is queued and returned immediately as `pending`. Poll [GET /jobs/`jobid`](/docs/api-flowmusic-v1/get-flowmusic-jobs-jobid) until `status` is `completed` or `failed`. ```json { "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:1234-user@email.com-bot:flowmusic", "email": "user@email.com", "operation": "remix", "status": "pending", "created_at": "2026-06-01T18:40:42.412Z", "request": { "operation": "remix", "clip": "user:1234-...-clip:...", "lyrics": "[Verse 1]\n...", "mode": "async" } } ``` **400** **400 Bad Request** Validation error — an unknown `operation`, a missing required field for the chosen operation (e.g. `replace` without `mask_start_s`/`mask_end_s`, or `effect` without `effect`), or a `clip` that isn't a clip-type asset ID. ```json { "error": "instruction required for operation=extend", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "Unauthorized", "code": 401 } ``` **402** **402 Payment Required** The targeted Flow Music account has insufficient credits to complete the edit. Top up its credit balance (or target a funded account with `email`), then retry. ```json { "error": "recipes/create failed (402): {\"detail\":\"User has insufficient credits\"}", "code": 402 } ``` **404** **404** The `clip`'s account isn't configured under your useapi.net account, or the source clip no longer exists on Flow Music. ```json { "error": "source clip not found on FlowMusic", "code": 404 } ``` **422** **422** The edit produced no audio (e.g. a content-moderation refusal — a terminal `status: "failed"` record), or the source clip can't be edited (an uploaded clip has no `conversation_id`). ```json { "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:1234-user@email.com-bot:flowmusic", "email": "user@email.com", "operation": "cover", "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 edit" }, "request": { "operation": "cover", "clip": "user:1234-...-clip:..." } } ``` **429** **429 Too Many Requests** Passed through from Flow Music when the `clip`'s account is already running too many concurrent jobs — retry once one finishes. ```json { "error": "producer/tool-call failed (429): {\"detail\":\"Too Many Requests\"}", "code": 429 } ``` **596** **596 Account Error** The `clip`'s account is in an error state and can't be used — re-add it via [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). ```json { "error": "Account user@email.com in error state: refresh token rejected", "code": 596 } ``` ### Model Same job-record shape as [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music), plus a top-level `operation`. The `request` echoes the edit body you submitted. (`operation: stems` returns a flat manifest of the 4 stem clips instead — see [operation: stems](#operation-stems).) **200 Completed** ```typescript { jobid: string // job:<uuid>-user:<id>-<email>-bot:flowmusic email: string operation: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' | 'stems' status: 'completed' | 'pending' | 'failed' created_at: string // ISO 8601 timestamp completed_at?: string // present when terminal duration_ms?: number // wall-clock render 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 // m4a download URL wav_url: string // wav download URL image_url: string | null // auto-generated artwork URL }> request: { // the edit body you submitted, echoed back verbatim operation: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' | 'stems' clip: string model?: 'lyria-3.5' | 'lyria-3-pro' // cover/extend/replace/remix — inert on effect/stems seed?: number // common — pins the result title?: string // common mode?: 'sync' | 'async' // common replyUrl?: string // common — webhook replyRef?: string // common — webhook reference effect?: 'Trim' | 'Fade' | 'Gain' | 'Reverb' | 'Pan' | 'Equalizer' // effect gain_db?: number // effect=Gain (-30..30) mix?: number // effect=Reverb (0..1) room_size?: number // effect=Reverb (0..1) pan?: number // effect=Pan (-1..1) bass_db?: number // effect=Equalizer (-12..12) mid_db?: number // effect=Equalizer (-12..12) treble_db?: number // effect=Equalizer (-12..12) fade_in_s?: number // effect=Fade fade_out_s?: number // effect=Fade start_s?: number // effect=Trim end_s?: number // effect=Trim instruction?: string // extend / replace / cover extend_s?: number // extend (1..300) extend_from_s?: number // extend mask_start_s?: number // replace mask_end_s?: number // replace strength?: number // cover (0..1) lyrics?: string // remix prompt?: string // remix } } ``` **201 Pending** ```typescript { jobid: string // job:<uuid>-user:<id>-<email>-bot:flowmusic email: string operation: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' | 'stems' status: 'pending' created_at: string // ISO 8601 timestamp request: { } // the edit body you submitted — same shape as the 200 (Completed) model above } ``` ### Examples **Curl** ``` bash # Cover (restyle) — instruction optional curl -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -X POST "https://api.useapi.net/v1/flowmusic/music/edit" \ -d '{ "operation": "cover", "clip": "user:1234-user@email.com-clip:...", "strength": 0.7 }' ``` **JavaScript** ``` javascript const response = await fetch('https://api.useapi.net/v1/flowmusic/music/edit', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ operation: 'remix', clip: 'user:1234-user@email.com-clip:...', lyrics: '[Verse 1]\nNeon rain on the avenue\n[Chorus]\nWe rise again' }) }); console.log(await response.json()); ``` **Python** ``` python import requests response = requests.post( 'https://api.useapi.net/v1/flowmusic/music/edit', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}, json={'operation': 'effect', 'clip': 'user:1234-user@email.com-clip:...', 'effect': 'Gain', 'gain_db': 6} ) print(response.status_code, response.json()) ``` ### Try It <script> function displayFlowMusicClips(response, elementId) { const container = document.getElementById(`${elementId}-media-links`); if (!container) return; container.innerHTML = ''; const clips = response.clips || []; if (clips.length === 0) { container.style.display = 'none'; return; } container.innerHTML = '<div class="media-links-container"><strong>Result clips:</strong></div>' + clips.map((c, i) => { const title = c.stem_type ? `${c.title || ('Stem ' + (i + 1))} (${c.stem_type})` : (c.title || `Clip ${i + 1}`); const cover = c.image_url ? `<a href="${c.image_url}" target="_blank" rel="noopener noreferrer" title="Open full image in a new tab"><img src="${c.image_url}" alt="cover" style="max-width:96px;border-radius:6px;vertical-align:middle;margin-right:8px;cursor:zoom-in;"></a>` : ''; const audio = c.audio_url ? `<audio src="${c.audio_url}" controls style="vertical-align:middle;"></audio>` : ''; return `<div style="margin:6px 0;">${cover}${audio}<div><small>${escHtml(title)}</small></div></div>`; }).join(''); container.style.display = 'block'; } async function apiTestMusicEditFlowMusic() { const data = { method: 'POST', headers: { 'Authorization': `Bearer ${document.getElementById('post-music-edit-FlowMusic-token').value}`, 'Content-Type': 'application/json' } }; const v = (id) => document.getElementById(`post-music-edit-FlowMusic-${id}`)?.value?.trim(); const str = (id) => { const x = v(id); return x ? x : undefined; }; const num = (id) => { const x = v(id); return x ? parseFloat(x) : undefined; }; const seedVal = v('seed'); const body = { operation: v('operation'), clip: v('clip'), model: str('model'), seed: seedVal ? parseInt(seedVal) : undefined, title: str('title'), mode: str('mode'), replyUrl: str('replyUrl'), replyRef: str('replyRef'), effect: str('effect'), gain_db: num('gain_db'), mix: num('mix'), room_size: num('room_size'), pan: num('pan'), bass_db: num('bass_db'), mid_db: num('mid_db'), treble_db: num('treble_db'), fade_in_s: num('fade_in_s'), fade_out_s: num('fade_out_s'), start_s: num('start_s'), end_s: num('end_s'), instruction: str('instruction'), extend_s: num('extend_s'), extend_from_s: num('extend_from_s'), mask_start_s: num('mask_start_s'), mask_end_s: num('mask_end_s'), strength: num('strength'), lyrics: str('lyrics'), prompt: str('prompt') }; data.body = JSON.stringify(body); const mediaLinks = document.getElementById('post-music-edit-FlowMusic-media-links'); if (mediaLinks) mediaLinks.style.display = 'none'; const status = await apiExecute(`https://api.useapi.net/v1/flowmusic/music/edit`, 'post-music-edit-FlowMusic', data); if (status === 200) { try { const response = JSON.parse(document.getElementById('post-music-edit-FlowMusic-response-json').innerText); displayFlowMusicClips(response, 'post-music-edit-FlowMusic'); } catch (e) { console.error('clip display failed', e); } } } </script> <form id="post-music-edit-FlowMusic" onsubmit="return false;" class="input-form"> <div class="input-field"> <div class="input-field-row"> <label for="post-music-edit-FlowMusic-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="post-music-edit-FlowMusic-token" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-operation"><span>operation<small> (required)</small></span> <select id="post-music-edit-FlowMusic-operation" class="input-element" required aria-required="true"> <option value="effect">effect</option> <option value="extend">extend</option> <option value="replace">replace</option> <option value="cover">cover</option> <option value="remix">remix</option> <option value="stems">stems</option> </select> </label> <label for="post-music-edit-FlowMusic-clip"><span>clip<small> (required, encoded clip asset id)</small></span> <input id="post-music-edit-FlowMusic-clip" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-model"><span>model<small> (cover/extend/replace/remix)</small></span> <select id="post-music-edit-FlowMusic-model" class="input-element"> <option value="">lyria-3-pro (default)</option> <option value="lyria-3.5">lyria-3.5</option> </select> </label> <label for="post-music-edit-FlowMusic-seed"><span>seed<small> (optional, integer ≥ 0)</small></span> <input id="post-music-edit-FlowMusic-seed" type="number" class="input-element" min="0" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-title"><span>title<small> (optional, result clip title)</small></span> <input id="post-music-edit-FlowMusic-title" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-instruction"><span>instruction<small> (extend/replace required, cover optional)</small></span> <textarea id="post-music-edit-FlowMusic-instruction" class="input-element" rows="3" style="resize: both;"></textarea> </label> <label for="post-music-edit-FlowMusic-lyrics"><span>lyrics<small> (remix, required)</small></span> <textarea id="post-music-edit-FlowMusic-lyrics" class="input-element" rows="3" style="resize: both;"></textarea> </label> <label for="post-music-edit-FlowMusic-prompt"><span>prompt<small> (remix, optional sound override)</small></span> <input id="post-music-edit-FlowMusic-prompt" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-effect"><span>effect<small> (effect, required — Trim/Fade/Gain/Reverb/Pan/Equalizer)</small></span> <select id="post-music-edit-FlowMusic-effect" class="input-element"> <option value=""></option> <option value="Trim">Trim</option> <option value="Fade">Fade</option> <option value="Gain">Gain</option> <option value="Reverb">Reverb</option> <option value="Pan">Pan</option> <option value="Equalizer">Equalizer</option> </select> </label> <label for="post-music-edit-FlowMusic-gain_db"><span>gain_db<small> (effect=Gain, −30…30)</small></span> <input id="post-music-edit-FlowMusic-gain_db" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-mix"><span>mix<small> (effect=Reverb, 0…1)</small></span> <input id="post-music-edit-FlowMusic-mix" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-room_size"><span>room_size<small> (effect=Reverb, 0…1)</small></span> <input id="post-music-edit-FlowMusic-room_size" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-pan"><span>pan<small> (effect=Pan, −1…1)</small></span> <input id="post-music-edit-FlowMusic-pan" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-bass_db"><span>bass_db<small> (effect=Equalizer, −12…12)</small></span> <input id="post-music-edit-FlowMusic-bass_db" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-mid_db"><span>mid_db<small> (effect=Equalizer, −12…12)</small></span> <input id="post-music-edit-FlowMusic-mid_db" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-treble_db"><span>treble_db<small> (effect=Equalizer, −12…12)</small></span> <input id="post-music-edit-FlowMusic-treble_db" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-fade_in_s"><span>fade_in_s<small> (effect=Fade, seconds)</small></span> <input id="post-music-edit-FlowMusic-fade_in_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-fade_out_s"><span>fade_out_s<small> (effect=Fade, seconds)</small></span> <input id="post-music-edit-FlowMusic-fade_out_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-start_s"><span>start_s<small> (effect=Trim, seconds)</small></span> <input id="post-music-edit-FlowMusic-start_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-end_s"><span>end_s<small> (effect=Trim, seconds)</small></span> <input id="post-music-edit-FlowMusic-end_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-extend_s"><span>extend_s<small> (extend, seconds 1–300)</small></span> <input id="post-music-edit-FlowMusic-extend_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-extend_from_s"><span>extend_from_s<small> (extend, seconds)</small></span> <input id="post-music-edit-FlowMusic-extend_from_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-mask_start_s"><span>mask_start_s<small> (replace, required, seconds)</small></span> <input id="post-music-edit-FlowMusic-mask_start_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-mask_end_s"><span>mask_end_s<small> (replace, required, seconds)</small></span> <input id="post-music-edit-FlowMusic-mask_end_s" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-strength"><span>strength<small> (cover, 0…1)</small></span> <input id="post-music-edit-FlowMusic-strength" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-mode"><span>mode<small> (optional — ignored by stems)</small></span> <select id="post-music-edit-FlowMusic-mode" class="input-element"> <option value="">sync (default)</option> <option value="async">async</option> </select> </label> <label for="post-music-edit-FlowMusic-replyUrl"><span>replyUrl<small> (optional, webhook URL)</small></span> <input id="post-music-edit-FlowMusic-replyUrl" type="text" class="input-element" oninput="this.size = this.value.length"> </label> <label for="post-music-edit-FlowMusic-replyRef"><span>replyRef<small> (optional, webhook reference)</small></span> <input id="post-music-edit-FlowMusic-replyRef" type="text" class="input-element" oninput="this.size = this.value.length"> </label> </div> <button id="post-music-edit-FlowMusic-button" class="btn btn-primary fs-3" type="submit" onclick="apiTestMusicEditFlowMusic()">Go</button> </div> </form> <div id="post-music-edit-FlowMusic-media-links" style="display:none;"></div> <div id="post-music-edit-FlowMusic-response" class="response-placeholder visible-false"></div> === URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music-lyrics === Document URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music-lyrics --- layout: default title: <code class="language-plaintext highlighter-rouge background-method-post">POST</code> music/lyrics description: "Generate structured [Verse]/[Chorus] lyrics from a prompt without rendering audio via POST music/lyrics in the useapi.net FlowMusic API v1." parent: FlowMusic API v1 nav_order: 220 permalink: /docs/api-flowmusic-v1/post-flowmusic-music-lyrics --- ## Generate lyrics <small>June 3, 2026</small> --- Generate `[Verse]`/`[Chorus]`-structured lyrics from a prompt, **without** producing audio. It runs the agent, so it uses a very small amount of credit (token usage), but renders no song. > Flow Music has no dedicated lyrics-only model — this endpoint drives the song agent to write lyrics (and a matching `sound_prompt`) **without** generating audio. It reads the agent's structured `lyrics__create` result, so lyrics come back reliably even when the agent's chat reply is conversational; a `422` only happens when the agent produced no lyrics at all. For lyrics bound to an actual track, use [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music) — every generated clip returns `clip.lyrics`. > **https://api.useapi.net/v1/flowmusic/music/lyrics** ### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Request Body ```json { "prompt": "a nostalgic song about a long road trip home", "structure": "Verse 1 / Chorus / Verse 2 / Chorus / Bridge / Outro" } ``` - `email` is optional, which configured account to use. - `prompt` is **required**, the song concept. 1–2,000 characters. - `structure` is optional, a free-text section scaffold to shape the layout. ≤2,000 characters. ### Responses **200** **200 OK** ```json { "email": "user@email.com", "title": "Road Home", "lyrics": "[Verse 1]\nHighway humming under the wheels\n[Chorus]\nTaking the long way home", "sound_prompt": "Indie folk, warm acoustic guitar, 80 BPM, intimate male vocal", "source": "lyrics-create", "audio_create_song_fired": false, "credits_burned": 0 } ``` **401** **401 Unauthorized** — invalid API token. **402** **402 Payment Required** The targeted Flow Music account has insufficient credits. Generating lyrics runs the agent, which draws a small amount of credit even though no audio is rendered, so this endpoint can still run an account dry. Top up its credit balance (or target a funded account with `email`), then retry. ```json { "error": "FlowMusic conversation failed (402): {\"detail\":\"User has insufficient credits\"}", "code": 402 } ``` **422** **422** — rare: the agent produced no lyrics at all (no structured result and no tagged text block). Retry, or use [POST /music](/docs/api-flowmusic-v1/post-flowmusic-music) and read `clip.lyrics`. ```json { "email": "user@email.com", "error": { "code": "no_lyrics", "message": "..." }, "agent_text": "..." } ``` **596** **596 Account Error** The account targeted by `email` is in an error state and can't be used — re-add it via [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). The `error` field returns whatever reason was recorded for the account. ```json { "error": "Account user@email.com in error state: refresh token rejected", "code": 596 } ``` ### Model ```typescript { email: string title: string | null lyrics: string // [Verse]/[Chorus]-tagged sound_prompt: string | null // a matching style/production prompt, when the agent wrote one source: string // 'lyrics-create' (agent's structured result) | 'text-part-fallback' audio_create_song_fired: boolean // true only if the agent also kicked off a render (normally false) credits_burned: number | null // 0 when no song was rendered — the agent chat still spends a tiny amount of credit; null if a render unexpectedly fired } ``` ### Examples **Curl** ``` bash curl -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -X POST "https://api.useapi.net/v1/flowmusic/music/lyrics" \ -d '{ "prompt": "a nostalgic song about a long road trip home" }' ``` **Python** ``` python import requests response = requests.post( 'https://api.useapi.net/v1/flowmusic/music/lyrics', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}, json={'prompt': 'a nostalgic song about a long road trip home'} ) print(response.status_code, response.json()) ``` ### Try It <script> async function apiTestMusicLyricsFlowMusic() { const data = { method: 'POST', headers: { 'Authorization': `Bearer ${document.getElementById('post-music-lyrics-FlowMusic-token').value}`, 'Content-Type': 'application/json' } }; let email = document.getElementById(`post-music-lyrics-FlowMusic-email`)?.value; let prompt = document.getElementById(`post-music-lyrics-FlowMusic-prompt`)?.value; let structure = document.getElementById(`post-music-lyrics-FlowMusic-structure`)?.value; const url = `https://api.useapi.net/v1/flowmusic/music/lyrics`; data.body = JSON.stringify({ email: email || undefined, prompt, structure: structure || undefined, }); await apiExecute(url, 'post-music-lyrics-FlowMusic', data); } </script> <form id="post-music-lyrics-FlowMusic" onsubmit="return false;" class="input-form"> <div class="input-field"> <div class="input-field-row"> <label for="post-music-lyrics-FlowMusic-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="post-music-lyrics-FlowMusic-token" type="text" class="input-element" required aria-required="true" oninput="this.size = this.value.length"> </label> <label for="post-music-lyrics-FlowMusic-email"><span>email<small> (optional)</small></span> <input id="post-music-lyrics-FlowMusic-email" type="text" class="input-element" placeholder="user@email.com"> </label> <label for="post-music-lyrics-FlowMusic-prompt"><span>prompt</span> <textarea id="post-music-lyrics-FlowMusic-prompt" class="input-element" rows="3" required aria-required="true" style="resize: both;"></textarea> </label> <label for="post-music-lyrics-FlowMusic-structure"><span>structure<small> (optional, section scaffold)</small></span> <input id="post-music-lyrics-FlowMusic-structure" type="text" class="input-element" oninput="this.size = this.value.length"> </label> </div> <button id="post-music-lyrics-FlowMusic-button" class="btn btn-primary fs-3" type="submit" onclick="apiTestMusicLyricsFlowMusic()">Go</button> </div> </form> <div id="post-music-lyrics-FlowMusic-response" class="response-placeholder visible-false"></div> === URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music === Document URL: https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music --- layout: default title: <code class="language-plaintext highlighter-rouge background-method-post">POST</code> music description: "Generate a complete song from a text prompt via POST music in the useapi.net FlowMusic API v1 — custom lyrics, instrumental mode, and A/B clip output." parent: FlowMusic API v1 nav_order: 200 permalink: /docs/api-flowmusic-v1/post-flowmusic-music --- ## Generate a song <small>June 3, 2026 (August 12, 2026)</small> --- Generate a complete song from a text prompt using [Lyria](https://deepmind.google/models/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 ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ### Request Body ```json { "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](/docs/api-flowmusic-v1/get-flowmusic-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](/docs/api-flowmusic-v1/post-flowmusic-files) or [POST /files/generate](/docs/api-flowmusic-v1/post-flowmusic-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](/docs/api-flowmusic-v1/post-flowmusic-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 — blocks until the song is ready, ~40–150 s) or `async` (returns `201` immediately with a `jobid`; poll [GET /jobs/`jobid`](/docs/api-flowmusic-v1/get-flowmusic-jobs-jobid) for the result). In `sync` your connection must stay open the whole time — if it drops the result is lost, so prefer `async` on mobile, flaky networks, or short-timeout platforms. - `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`](/docs/api-flowmusic-v1/get-flowmusic-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** **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. ```json { "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:1234-user@email.com-bot:flowmusic", "email": "user@email.com", "status": "completed", "created_at": "2026-06-01T18:40:42.412Z", "completed_at": "2026-06-01T18:42:55.123Z", "duration_ms": 132711, "clips": [ { "clip": "user:1234-user@email.com-clip: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** **201 Created** **Async mode** (`"mode": "async"`) — the job is queued and returned immediately as `pending`. Poll [GET /jobs/`jobid`](/docs/api-flowmusic-v1/get-flowmusic-jobs-jobid) until `status` is `completed` or `failed`. ```json { "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:1234-user@email.com-bot:flowmusic", "email": "user@email.com", "status": "pending", "created_at": "2026-06-01T18:40:42.412Z", "request": { "prompt": "upbeat funk groove, 110 bpm", "instrumental": true, "mode": "async" } } ``` **400** **400 Bad Request** Validation error (missing/invalid parameter, or no account configured). ```json { "error": "Parameter prompt is required", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "Unauthorized", "code": 401 } ``` **402** **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. ```json { "error": "FlowMusic conversation failed (402): {\"detail\":\"User has insufficient credits\"}", "code": 402 } ``` **422** **422** The model produced no audio (e.g. a content-moderation refusal). A terminal job record with `status: "failed"`. ```json { "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:1234-user@email.com-bot:flowmusic", "email": "user@email.com", "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** **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: ```json { "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): ```json { "error": "FlowMusic conversation failed (429): {\"detail\":\"Too Many Requests\"}", "code": 429 } ``` **596** **596 Account Error** The account targeted by `email` is in an error state and can't be used — re-add it via [POST /accounts](/docs/api-flowmusic-v1/post-flowmusic-accounts). The `error` field returns whatever reason was recorded for the account. ```json { "error": "Account user@email.com in error state: refresh token rejected", "code": 596 } ``` ### Model **200 Completed** ```typescript { 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 } } ``` **201 Pending** ```typescript { 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** ``` bash 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" }' ``` **JavaScript** ``` javascript 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); ``` **Python** ``` python 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 <script> function displayFlowMusicClips(response, elementId) { const container = document.getElementById(`${elementId}-media-links`); if (!container) return; container.innerHTML = ''; const clips = response.clips || []; if (clips.length === 0) { container.style.display = 'none'; return; } container.innerHTML = '<div class="media-links-container"><strong>Generated clips:</strong></div>' + clips.map((c, i) => { const title = c.title || `Clip ${i + 1}`; const cover = c.image_url ? `<a href="${c.image_url}" target="_blank" rel="noopener noreferrer" title="Open full image in a new tab"><img src="${c.image_url}" alt="cover" style="max-width:96px;border-radius:6px;vertical-align:middle;margin-right:8px;cursor:zoom-in;"></a>` : ''; const audio = c.audio_url ? `<audio src="${c.audio_url}" controls style="vertical-align:middle;"></audio>` : ''; return `<div style="margin:6px 0;">${cover}${audio}<div><small>${escHtml(title)}</small></div></div>`; }).join(''); container.style.display = 'block'; } async function apiExecutePostFlowMusicMusic() { const elementId = 'input'; const payload = {}; document.querySelectorAll('.input-query-param').forEach(input => { const value = input.value?.trim(); if (input.id.startsWith('input-') && value !== '' && value !== undefined) { const key = input.id.replace('input-', ''); if (key === 'seed') payload[key] = parseInt(value); else if (key === 'instrumental') payload[key] = value === 'true'; else payload[key] = value; } }); const data = { method: 'POST', headers: { 'Authorization': `Bearer ${document.getElementById('input-token').value}`, 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }; const mediaLinks = document.getElementById(`${elementId}-media-links`); if (mediaLinks) mediaLinks.style.display = 'none'; const status = await apiExecute('https://api.useapi.net/v1/flowmusic/music', elementId, data, { includeTimer: true }); if (status === 200) { try { const response = JSON.parse(document.getElementById(`${elementId}-response-json`).innerText); displayFlowMusicClips(response, elementId); } catch (e) { console.error('Failed to parse response for clip display:', e); } } } </script> <form id="input" class="input-form" onsubmit="return false;"> <div class="input-field"> <div class="input-field-row"> <label for="input-token"><span>API Token<small> (see <a href="/docs/start-here/setup-useapi">Setup useapi.net</a>)</small></span> <input id="input-token" type="text" class="input-element" required aria-required="true"> </label> <label for="input-prompt"><span>prompt<small> (required)</small></span> <input id="input-prompt" type="text" class="input-element input-query-param" required aria-required="true" placeholder="lo-fi hip hop, mellow piano, 80 bpm"> </label> <label for="input-instrumental"><span>instrumental</span> <select id="input-instrumental" class="input-element input-query-param"> <option value="">false (default)</option> <option value="true">true (instrumental — no vocals)</option> </select> </label> <label for="input-lyrics"><span>lyrics<small> (optional, [Verse]/[Chorus]-tagged)</small></span> <input id="input-lyrics" type="text" class="input-element input-query-param" placeholder="[Verse 1] ... [Chorus] ..."> </label> <label for="input-ghostwriter"><span>ghostwriter<small> (lyrics-writer version)</small></span> <select id="input-ghostwriter" class="input-element input-query-param"> <option value=""></option> <option value="standard">standard</option> <option value="pro">pro</option> </select> </label> <label for="input-model"><span>model<small> (music model)</small></span> <select id="input-model" class="input-element input-query-param"> <option value="">lyria-3-pro (default)</option> <option value="lyria-3.5">lyria-3.5</option> </select> </label> <label for="input-email"><span>email<small> (optional)</small></span> <input id="input-email" type="text" class="input-element input-query-param" placeholder="user@email.com"> </label> <label for="input-refImage1"><span>refImage1<small> (optional, encoded image asset id from <a href="/docs/api-flowmusic-v1/post-flowmusic-files" target="_blank">POST /files</a>)</small></span> <input id="input-refImage1" type="text" class="input-element input-query-param" placeholder="user:1234-user@email.com-image:..."> </label> <label for="input-refAudio1"><span>refAudio1<small> (optional, encoded audio asset id from <a href="/docs/api-flowmusic-v1/post-flowmusic-files" target="_blank">POST /files</a>)</small></span> <input id="input-refAudio1" type="text" class="input-element input-query-param" placeholder="user:1234-user@email.com-audio:..."> </label> <label for="input-mode"><span>mode</span> <select id="input-mode" class="input-element input-query-param"> <option value="">sync (default)</option> <option value="async">async</option> </select> </label> <label for="input-replyUrl"><span>replyUrl<small> (webhook URL)</small></span> <input id="input-replyUrl" type="text" class="input-element input-query-param" placeholder="https://your-domain.com/webhook"> </label> <label for="input-replyRef"><span>replyRef<small> (custom reference)</small></span> <input id="input-replyRef" type="text" class="input-element input-query-param" placeholder="my-custom-id-123"> </label> </div> <button id="input-button" class="btn btn-primary fs-3" type="submit" onclick="apiExecutePostFlowMusicMusic()">Go</button> </div> </form> <div id="input-media-links" style="display:none;"></div> <div id="input-response" class="response-placeholder visible-false"></div> === Cross-reference: General Q&A === For cross-cutting tips (rate limiting, prompt moderation, common patterns) see https://useapi.net/assets/aibot/qa.txt WARNING: Q&A items are general-purpose and may reference deprecated APIs, sunsetted services, or scenarios not applicable to the API documented above. Cross-check against this service's endpoint documentation before applying any Q&A guidance.