How to Generate AI Music with Lyria 3 Pro via the Flow Music API

5 min read • July 19, 2026

Table of contents

  1. Introduction
  2. Capabilities and parameters
  3. Pricing
  4. Generate a song in two API calls
  5. Custom lyrics, instrumentals, and editing a song
  6. Batch-generate with a script
  7. Examples
  8. Frequently asked questions
  9. Conclusion

Introduction

Lyria 3 Pro is Google DeepMind’s text-to-music model — and the useapi.net Flow Music API runs it over plain REST at roughly 6–10× less than Google’s own $0.08-a-song API. Lyria 3 Pro powers Flow Music, Google Labs’ generator (formerly Producer AI, originally Riffusion). useapi.net drives your own Flow Music account: one prompt returns a complete, produced song — vocals, melody, and arrangement — and from there you can supply your own lyrics, force an instrumental, or edit a clip with cover, remix, extend, replace, effects, and stem-splitting.

Capabilities and parameters

Every song is generated with Lyria 3 Pro. Each call returns up to two clips (an A/B pair), each up to roughly three minutes long. The main fields on the music endpoint:

Parameter Type What it does
prompt string (required) Song description — style, mood, genre, instruments, BPM, vocal direction. 1–10,000 chars.
instrumental boolean true forces an instrumental (prepends an [Instrumental] tag). false (default) lets the model decide whether to sing.
lyrics string Your own [Verse]/[Chorus]-tagged lyrics (≤10,000 chars) — forces a vocal render of those exact words.
ghostwriter standard | pro Which lyrics-writer version writes the words when the model writes them. No effect if you supply your own lyrics.
mode sync | async sync (default) blocks ~40–150 s and returns the finished song. async returns a jobid to poll.
email string Which connected account to use. Omit it and the API load-balances across accounts with free capacity.

If you omit both instrumental and lyrics, the model decides whether to sing from your prompt alone. The endpoint also accepts replyUrl/replyRef webhooks and experimental refImage/refAudio reference hints — see the music endpoint docs for the full body.

Generation is only the first step — the music/edit endpoint reworks any existing clip with six operations:

Operation What it does
cover Restyle the whole song (a Lyria 3 Pro cover)
remix Re-sing with edited lyrics
extend Add 1–300 s of new music (default 150 s), at the end or from a chosen point
replace Regenerate a specific time section
effect Apply Trim, Fade, Gain, Reverb, Pan, or Equalizer
stems Split into four stems — drums, bass, vocals, other

The editing section below shows the request shapes for each.

Pricing

You pay your normal Flow Music account plan for the underlying credits, plus a single flat $15/month to useapi.net that covers API access to every supported service — there are no per-generation API surcharges. Flow Music’s own plans (from the Flow Music pricing page) work out to roughly $0.008–$0.013 per song on paid tiers — about 6–10× cheaper than the $0.08/song on Google’s official Lyria 3 Pro API, and that includes cover, remix, extend/replace, effects, and stem-splitting. Even the Free plan generates a little each day from daily top-up credits, and all downloads (mp3, wav, m4a, stems) are free. See the Flow Music API overview for the full cost calculator, and Setup Flow Music to connect an account.

Generate a song in two API calls

You need a useapi.net API token and a connected Flow Music account — export the token so the curl examples below run as-is: export USEAPI_TOKEN="user:1234-...". The fastest reliable workflow is asynchronous: the create call returns a jobid immediately, then you poll until the song is ready.

1. Submit the jobPOST https://api.useapi.net/v1/flowmusic/music:

curl -X POST "https://api.useapi.net/v1/flowmusic/music" \
  -H "Authorization: Bearer $USEAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "warm indie folk ballad, acoustic guitar, soft female vocals, 70 bpm, wistful and hopeful",
    "ghostwriter": "pro",
    "mode": "async"
  }'

In async mode the response returns immediately with 201 Created, a jobid, and status: "pending":

{
  "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic",
  "email": "[email protected]",
  "status": "pending",
  "created_at": "2026-06-01T18:40:42.412Z",
  "request": { "prompt": "warm indie folk ballad...", "mode": "async" }
}

2. Poll for the resultGET https://api.useapi.net/v1/flowmusic/jobs/{jobid} (the jobid is URL-encoded in the path — it contains : and @):

curl "https://api.useapi.net/v1/flowmusic/jobs/JOBID" \
  -H "Authorization: Bearer $USEAPI_TOKEN"

When status is completed, the finished audio lives in the clips[] array — audio_url is the signed .m4a, and wav_url is the lossless WAV:

{
  "jobid": "job:aaaabbbb-...-bot:flowmusic",
  "status": "completed",
  "duration_ms": 132711,
  "clips": [
    {
      "clip": "user:[email protected]:a1b2c3d4-...",
      "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",
      "audio_url": "https://storage.googleapis.com/...a1b2c3d4.m4a",
      "wav_url": "https://storage.googleapis.com/...a1b2c3d4.wav",
      "image_url": "https://storage.googleapis.com/...b2c3d4e5.jpg"
    }
  ]
}

Lyria 3 Pro typically finishes in 40–150 seconds. Result URLs are signed, so download promptly. Prefer not to poll? mode: "sync" (the default) blocks until the song is ready and returns the same completed record inline with 200 OK — handy for quick tests, but on mobile or flaky networks prefer async, since a dropped connection in sync mode loses the result. You can also pass a replyUrl to receive a webhook when the job completes. A job can come back status: "failed" (e.g. a content-moderation refusal), and the create call may return 402 (insufficient credits), 422 (prompt moderated / no audio), or 429 (all accounts busy) — see the endpoint docs for the full list.

Custom lyrics, instrumentals, and editing a song

You control the voicing entirely from the request body. Set instrumental: true for a purely instrumental track, or paste tagged lyrics to force a sung render of your exact words:

# Instrumental only
curl -X POST "https://api.useapi.net/v1/flowmusic/music" \
  -H "Authorization: Bearer $USEAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "energetic synthwave, driving bass, retro 80s, 120 bpm", "instrumental": true }'

# Your own lyrics → forces a vocal render of those words
curl -X POST "https://api.useapi.net/v1/flowmusic/music" \
  -H "Authorization: Bearer $USEAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "soulful R&B, lush keys, 90 bpm",
    "lyrics": "[Verse 1]\nCity lights blur in the rain\n[Chorus]\nAnd I will wait for the morning sun"
  }'

Once you have a clip’s id, the music/edit endpoint runs any of the six operations from the table above. For example, to extend a song by 30 seconds:

curl -X POST "https://api.useapi.net/v1/flowmusic/music/edit" \
  -H "Authorization: Bearer $USEAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "extend",
    "clip": "CLIP_ID_FROM_A_PREVIOUS_GENERATION",
    "extend_s": 30
  }'

See the editing docs for each operation’s parameters.

Batch-generate with a script

Finding the right track takes many attempts, and running them by hand is tedious. The Node.js script below reads a list of prompts from prompts.json, submits each one to the music endpoint in async mode, polls every job until it is done, then downloads all the resulting .m4a clips — so you can queue a batch and come back to a folder of finished songs.

You need Node.js v21 or newer. Put prompts.json and flowmusic.mjs in the same folder and run node ./flowmusic.mjs API_TOKEN EMAIL, where API_TOKEN is your useapi.net API token and EMAIL is the configured Flow Music account email you want to use. Each entry’s prompt is required; the optional instrumental, lyrics, and ghostwriter fields map straight to the music endpoint.

Expand prompts.json
[
    {
        "prompt": "lo-fi hip hop, mellow piano, 80 bpm. By default the model decides whether to sing based on your prompt."
    },
    {
        "prompt": "warm indie folk ballad, acoustic guitar, soft female vocals, 70 bpm, wistful and hopeful",
        "ghostwriter": "pro"
    },
    {
        "prompt": "energetic synthwave, driving bass, retro 80s, 120 bpm",
        "instrumental": true
    },
    {
        "prompt": "soulful R&B, lush keys, 90 bpm. Provide your own [Verse]/[Chorus]-tagged lyrics to force a vocal render of those exact words. For all parameters see https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music",
        "lyrics": "[Verse 1]\nCity lights blur in the rain\n[Chorus]\nAnd I will wait for the morning sun"
    }
]
Expand flowmusic.mjs script
/*

Script version 1.0, July 19, 2026

Script to batch-generate music using prompts with the Flow Music API v1 by useapi.net 🚀
Generates complete songs with Google's Lyria 3 Pro via the music endpoint.
For more details visit https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music

Installation Instructions:
==========================

You need Node.js v21 or newer installed to run this script. Download and install Node.js from:

- Windows, macOS, Linux: https://nodejs.org/

After installation, verify by running the following command in a terminal:

   node -v

Running the Script:
===================

Usage: node flowmusic.mjs <API_TOKEN> <EMAIL> [PROMPTS_FILE]

Replace API_TOKEN with your actual useapi.net API token, see https://useapi.net/docs/start-here/setup-useapi
Replace EMAIL with configured Flow Music email account, see https://useapi.net/docs/start-here/setup-flowmusic
If optional PROMPTS_FILE not provided prompts.json will be used.

Example:
--------

node flowmusic.mjs user:1234-abcdefhijklmnopqrstuv [email protected]

This command executes the script using API token user:1234-abcdefhijklmnopqrstuv with [email protected] Flow Music account email.

Changelog:
==========

- July 19, 2026: Initial release. Submits prompts to the music endpoint in async mode and downloads the resulting m4a clips.

*/

import readline from 'node:readline';
import fs from 'fs/promises';
import { writeFile } from 'node:fs/promises';
import { Readable } from 'node:stream';


// Constants
const RESULTS_FILE = 'flowmusic_results.txt';
const ERRORS_FILE = 'flowmusic_errors.txt';
const DEFAULT_PROMPTS_FILE = 'prompts.json';
const SLEEP_429 = 10 * 1000; // in milliseconds
const MAX_429_RETRIES = 6;   // give up a prompt after this many consecutive 429s (all accounts busy)
const SLEEP_POLL = 15 * 1000; // in milliseconds

const urlAccounts = 'https://api.useapi.net/v1/flowmusic/accounts';
const urlMusic = 'https://api.useapi.net/v1/flowmusic/music';
const urlJobs = 'https://api.useapi.net/v1/flowmusic/jobs/';

// Utility to sleep for given milliseconds
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const elapsedTimeSec = (start) => (Date.now() - start) / 1000;

// Function to fetch configured Flow Music API accounts
async function fetchAccounts(apiToken) {
    const response = await fetch(urlAccounts, {
        headers: {
            'Accept': 'application/json',
            'Authorization': `Bearer ${apiToken}`
        }
    });

    if (!response.ok) {
        console.error(`⛔ Error fetching accounts (HTTP ${response.status}): ${response.statusText}`);
        process.exit(1);
    }

    return response.json();
}

// Submit a single prompt to the music endpoint in async mode.
// Returns the HTTP status; on 201 the jobid is appended to RESULTS_FILE.
async function submitMusic(apiToken, email, prompt, index) {
    const { prompt: text, instrumental, lyrics, ghostwriter } = prompt;

    console.log(`🚀 Lyria 3 Pro » Prompt #${index} • account ${email}${instrumental ? 'instrumental' : 'auto vocals'} …`);

    const body = JSON.stringify({
        email,
        prompt: text,
        instrumental,
        lyrics,
        ghostwriter,
        mode: 'async'
    });

    const createResponse = await fetch(urlMusic, {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiToken}`
        },
        body
    });

    const createBody = await createResponse.text();

    // 201 Created — async job queued; 200 OK — sync result (returned if mode is overridden).
    if (createResponse.status == 201 || createResponse.status == 200) {
        const json = JSON.parse(createBody);
        const { jobid } = json;
        if (jobid) {
            await fs.appendFile(RESULTS_FILE, `${jobid},#${index}:${text}\n`);
            console.log(`✅ jobid`, jobid);
            return 201;
        } else {
            const error = `No jobid found in HTTP ${createResponse.status} response`;
            console.log(`❓ ${error}`, createBody);
            await fs.appendFile(ERRORS_FILE, `${error},#${index}:${text}\n`);
            return 500;
        }
    } else {
        switch (createResponse.status) {
            case 429:
                console.log(`🔄️ Retry on HTTP ${createResponse.status}`);
                break;
            case 422:
                console.log(`🛑 MODERATED prompt — the model declined to generate audio`, createBody);
                await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${text}\n`);
                break;
            case 402:
                console.log(`🛑 account has insufficient credits`, createBody);
                await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${text}\n`);
                break;
            case 596:
                console.log(`🛑 account in error state — re-add it at https://useapi.net/docs/start-here/setup-flowmusic`, createBody);
                await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${text}\n`);
                break;
            default:
                console.log(`❗ FAILED with HTTP ${createResponse.status}`, createBody);
                await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${text}\n`);
        }
        return createResponse.status;
    }
}

// Function to poll jobs and download generated audio clips
async function download(apiToken) {
    if (! await fileExists(RESULTS_FILE)) return;

    try {
        const resultsContent = await fs.readFile(RESULTS_FILE, 'utf8');
        const lines = resultsContent.trim().split('\n');

        for (const line of lines) {
            const [jobid, prompt] = line.split(',');

            console.log(`👉 ${jobid}`);

            while (true) {
                const response = await fetch(`${urlJobs}${encodeURIComponent(jobid)}`, {
                    headers: {
                        'Accept': 'application/json',
                        'Authorization': `Bearer ${apiToken}`
                    }
                });

                if (!response.ok) {
                    console.log(`🛑 Poll failed ${jobid} (HTTP ${response.status}):\n${prompt}\n`, await response.text());
                    break;
                }

                const jobResponseBody = await response.json();
                const { status, clips, error } = jobResponseBody;

                if (status == 'failed') {
                    console.error(`🛑 FAILED ${jobid} (${error?.code}: ${error?.message}):\n${prompt}\n`);
                    break;
                }

                if (status == 'completed') {
                    if (Array.isArray(clips) && clips.length > 0) {
                        // A single generation returns up to two clips (an A/B pair) — download all of them.
                        for (let c = 0; c < clips.length; c++) {
                            const { clip, audio_url } = clips[c];
                            const audioFilename = `${clip.replace(/[:/]/g, '_')}.m4a`;

                            if (await fileExists(audioFilename)) {
                                console.log(`⚠️ ${audioFilename} already exists. Skipping download.`);
                                continue;
                            }

                            if (audio_url) {
                                console.log(`✅ Downloading ${audio_url} to ${audioFilename}`);
                                try {
                                    const audioResponse = await fetch(audio_url);
                                    if (!audioResponse.ok) {
                                        console.error(`⛔ Unable to download ${jobid} (HTTP ${audioResponse.status}):\n${prompt}\n`, audio_url);
                                        continue;
                                    }
                                    const stream = Readable.fromWeb(audioResponse.body);
                                    await writeFile(audioFilename, stream);
                                } catch (err) {
                                    console.error(`⛔ Error during download: ${err}`);
                                }
                            } else {
                                console.error(`🛑 No audio_url for clip ${clip} (${jobid}):\n${prompt}\n`);
                            }
                        }
                    } else {
                        console.error(`🛑 ${jobid} completed but returned no clips:\n${prompt}\n`);
                    }

                    break;
                }

                console.log(`⌛ ${jobid} status (${status}) and is still in progress, waiting…`);
                await sleep(SLEEP_POLL);
            }
        }
    } catch (error) {
        console.log(`⛔ Error during download:`, error.stack || error);
    }
}

// Main function
async function main() {
    const apiToken = process.argv[2];
    const email = process.argv[3];
    const promptFile = process.argv[4] || DEFAULT_PROMPTS_FILE;

    if (!apiToken || !email) {
        console.error('Usage: node flowmusic.mjs <API_TOKEN> <EMAIL> [PROMPTS_FILE]');
        process.exit(1);
    }

    console.info('Script v1.0');

    console.info('Node version is: ' + process.version);

    try {
        if (await fileExists(RESULTS_FILE)) {
            let user_input;
            while (!['y', 'n'].includes(user_input)) {
                user_input = (await promptUser(`❔ ${RESULTS_FILE} file detected. Do you want to download the results now? (y/n): `))?.toLowerCase();
                if (user_input == 'y') {
                    await download(apiToken);
                    await fs.unlink(RESULTS_FILE);
                }
            }
        }

        const start = new Date();
        try {
            console.info('START EXECUTION', start);
            await execute(apiToken, email, promptFile); // Pass the promptFile to execute function
        }
        finally {
            console.info('COMPLETED', new Date());
            console.info('EXECUTION ELAPSED', diffInMinutesAndSeconds(start, new Date()));
        }

        try {
            console.info('START DOWNLOAD', start);
            await download(apiToken);
        }
        finally {
            console.info('TOTAL ELAPSED', diffInMinutesAndSeconds(start, new Date()));
        }
    } catch (error) {
        console.error('⛔ Error during execution:', error.stack || error);
    }
}

// Modify the execute function to accept promptFile as a parameter
async function execute(apiToken, email, promptFile) {
    const accounts = await fetchAccounts(apiToken);

    console.info(`Configured Flow Music API accounts (${Object.values(accounts).length}):`, Object.values(accounts).map(a => a.email).join(', '));

    if (Object.values(accounts).length <= 0) {
        console.error(`⛔ No configured Flow Music accounts found. Please refer to https://useapi.net/docs/start-here/setup-flowmusic`);
        process.exit(1);
    }

    if (!accounts[email]) {
        console.error(`⛔ Account ${email} not found. Please refer to https://useapi.net/docs/start-here/setup-flowmusic`);
        process.exit(1);
    }

    if (accounts[email].error) {
        console.error(`⛔ Account ${email} has pending error. Please re-add the account, see https://useapi.net/docs/start-here/setup-flowmusic`);
        process.exit(1);
    }

    const promptData = await fs.readFile(promptFile, 'utf8');
    const prompts = JSON.parse(promptData);
    console.log(`Total number of prompts to process`, prompts.length);

    let warnings = [];

    // Parameters accepted by this script for the music endpoint.
    // See https://useapi.net/docs/api-flowmusic-v1/post-flowmusic-music for the full parameter set.
    const supportedParams = ['prompt', 'instrumental', 'lyrics', 'ghostwriter'];

    const invalidKeys = (prompt) => Object.keys(prompt).filter(key => !key.startsWith('__') && !supportedParams.includes(key));

    for (let i = 1; i <= prompts.length; i++) {
        const prompt = prompts[i - 1];
        const { prompt: text, ghostwriter } = prompt;

        const notSupported = invalidKeys(prompt);
        if (notSupported.length)
            warnings.push(`⚠️  Following params not supported: ${notSupported.join(',')}. Prompt ${i}`);

        if (!text || typeof text !== 'string' || text.trim().length === 0)
            warnings.push(`⚠️  Please specify a non-empty prompt. Prompt ${i}`);

        if (typeof text === 'string' && text.length > 10000)
            warnings.push(`⚠️  prompt exceeds 10,000 characters. Prompt ${i}`);

        if (ghostwriter !== undefined && !['standard', 'pro'].includes(ghostwriter))
            warnings.push(`⚠️  ghostwriter must be 'standard' or 'pro'. Prompt ${i}`);
    }

    if (warnings.length > 0) {
        warnings.forEach(warning => console.warn(warning));
        console.error(`⛔ Execution stopped due to warnings.`);
        process.exit(1);
    }

    for (let i = 0; i < prompts.length; i++) {
        const prompt = prompts[i];
        let retries429 = 0;
        while (true) {
            const responseCode = await submitMusic(apiToken, email, prompt, i + 1);
            if (responseCode == 429) {
                if (++retries429 > MAX_429_RETRIES) {
                    console.error(`⛔ Gave up on prompt #${i + 1} after ${MAX_429_RETRIES} retries — all accounts still busy.`);
                    await fs.appendFile(ERRORS_FILE, `429 (gave up after ${MAX_429_RETRIES} retries),#${i + 1}\n`);
                    break;
                }
                await sleep(SLEEP_429);
            }
            else
                if (responseCode == 402 || responseCode == 596) {
                    process.exit(1);
                } else
                    break;
        }
    }
}

// Utility function to check if a file exists
async function fileExists(path) {
    try {
        await fs.access(path);
        return true;
    } catch {
        return false;
    }
}

// Function to prompt user input
async function promptUser(query) {
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    return new Promise((resolve) => rl.question(query, answer => {
        rl.close();
        resolve(answer);
    }));
}

function diffInMinutesAndSeconds(date1, date2) {
    const diffInSeconds = Math.floor((date2 - date1) / 1000);
    return `${Math.floor(diffInSeconds / 60)} minutes ${diffInSeconds % 60} seconds`;
};

main();

Examples

These are real songs generated with Lyria 3 Pro through the Flow Music API — each from a single text prompt, exactly as the workflow above produces them. Full prompts and curl for each are in the FlowMusic API v1 launch post.

Euphoric Currents — instrumental liquid drum & bass (instrumental: true), from FlowMusic API v1: Powered by Lyria 3 Pro:

Solid Ground — emotional pop ballad with a soaring female vocal (model-written lyrics), from FlowMusic API v1: Powered by Lyria 3 Pro:

Running on Empty — epic power ballad rendered from custom [Verse]/[Chorus] lyrics, from FlowMusic API v1: Powered by Lyria 3 Pro:

For more samples — including extend, cover, remix, studio effects, and AI-generated cover art — see the full launch post.

Frequently asked questions

Is there a Lyria 3 Pro API? Yes — two ways. Google offers Lyria 3 Pro directly through the Gemini API (self-serve via Google AI Studio). Or use useapi.net’s Flow Music API, which drives your own Flow Music account through a standard REST endpoint and adds cover, remix, extend, and stem-splitting on top. (See Pricing for the difference.)

Is this a Suno or Udio alternative? Yes. Like Suno and Udio, the Flow Music API generates full songs with vocals from a single text prompt — but it runs on Google DeepMind’s Lyria 3 Pro, and it adds cover, remix, extend, and stem-splitting, all under one flat $15/month useapi.net subscription.

Can I generate instrumental music or supply my own lyrics? Yes. Set instrumental: true to force an instrumental, or pass your own [Verse]/[Chorus]-tagged lyrics (≤10,000 chars) to force a vocal render of those exact words. If you provide neither, Lyria 3 Pro decides whether to sing based on your prompt. See Custom lyrics, instrumentals, and editing above.

What audio format do I get? Each completed clip carries a signed .m4a (audio_url) and a lossless .wav (wav_url) you can download directly. You can also fetch an .mp3 via GET /music/download. All downloads are free.

Do I need a Google or Flow Music account? Yes — you connect your own Flow Music account (Google sign-in) once during setup, and useapi.net drives it for you with your useapi.net API token. No Google Cloud project is needed. You can configure up to 50 accounts per useapi.net subscription.

How much does it cost? You keep your normal Flow Music plan for credits, plus a flat $15/month to useapi.net for API access to all services, with no per-generation surcharges. Flow Music’s paid plans work out to roughly $0.008–$0.013 per song — about 6–10× cheaper than the $0.08/song on Google’s official Lyria 3 Pro API. See Pricing above.

Can I cover, extend, or split a song into stems? Yes. The music/edit endpoint takes any generated clip and runs cover, remix, extend, replace, effect, or stems (which produces separate drums/bass/vocals/other clips). See Custom lyrics, instrumentals, and editing above.

How is this different from the official Google API? Google’s official Lyria 3 Pro runs through the Gemini API / AI Studio — your own Google Cloud project and API key, billed per song. useapi.net instead drives your own consumer Flow Music account over REST (just a useapi.net token), adds cover/remix/extend/replace/effects/stems on top of plain generation, and the same one subscription covers other AI services too.

Conclusion

Visit our Discord Server or Telegram Channel for any support questions and concerns.

We regularly post guides and tutorials on the YouTube Channel.

The full runnable example is in the flowmusic-api GitHub repo.

Cross posted