Music Generator

Music generation API

Send a description, get a song back as an MP3 and a WAV: instrumental, up to two minutes, royalty-free for commercial games and videos. The same songs as the generator: 10 a month free, 1,000 for $2 a month.

Quick start

  1. Get a key. Sign in on your Daydream dashboard, press Create, and copy the key (it's shown once).
  2. Make a song. POST /v1/songs with a description. It comes back at once, in line.
  3. Poll until it's done, every 2 seconds, then download takes[0].mp3_url.
curl https://gen.daydream.live/v1/songs \
  -H "Authorization: Bearer $DAYDREAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "a calm village theme with flute and harp", "loop": true}'

Base URL: https://gen.daydream.live/v1. Requests and responses are JSON. The OpenAPI spec describes every endpoint, for code generators and AI agents.

Keys

Send your Daydream API key on every request:

Authorization: Bearer <your key>

A key can do anything on its account, so keep it on your machine or your server: out of web pages, repositories and game builds you ship. Generate music in the editor, in a build step, or from your own backend, and ship the files.

Your songs

There are no credits. Each account has a number of songs a month, shared by the API and the generator page:

PlanSongs a month
Free10
Songs, $2 a month1,000
Studio Pro2,000
Studio Max5,000

One POST /v1/songs is one song, with one or two variations. It counts when you create it; if it fails, it's given back. The count starts again on the first of each month (UTC). Pricing

Make a song

POST /v1/songs

FieldTypeWhat it does
promptstring, requiredWhat the song is, 1 to 400 characters: genre, mood, instruments, scene. Instrumental only: words asking for vocals or lyrics are dropped. Artist names are refused.
durationnumberSeconds, 10 to 120. Default 120. Trimmed to whole bars with a short fade out (no fade on a loop).
bpminteger60 to 200. Default: a tempo the words name ("at 90 bpm"), else the genre's usual one, else 100.
keystringOne of the 24 major and minor keys: "C major", "F# minor", "A minor"… Default: none.
loopbooleanA seamless loop: made to repeat, in whole bars, no fade. 8 bars unless duration says otherwise. Default false.
seedinteger0 to 2147483647. Default random. Variation n uses seed + n − 1.
variations1 or 2How many versions. Default 1. Either way it's one song.

It answers 202 with the song, queued:

{
  "id": "sng_4hT2kq9XbV1nLm0pQe3rZa",
  "status": "queued",
  "position": 2,
  "prompt": "a calm village theme with flute and harp",
  "duration": 120,
  "bpm": 70,
  "key": null,
  "loop": true,
  "seed": 482113,
  "variations": 1,
  "created_at": "2026-10-15T09:12:03Z",
  "finished_at": null,
  "error": null,
  "takes": []
}

Get a song

GET /v1/songs/{id}

Poll it every 2 seconds until status is done or failed:

statusMeans
queuedIn line. position is its place (1 is next).
renderingBeing made.
doneReady: takes has one entry per variation.
failedIt didn't finish. error says why; the song is given back.
{
  "id": "sng_4hT2kq9XbV1nLm0pQe3rZa",
  "status": "done",
  "position": null,
  …
  "finished_at": "2026-10-15T09:12:15Z",
  "takes": [
    {
      "n": 1,
      "seed": 482113,
      "duration": 109.7,
      "waveform": [0.21, 0.34, 0.52, …],
      "mp3_url": "https://gen.daydream.live/v1/songs/sng_4hT2kq9XbV1nLm0pQe3rZa/1.mp3",
      "wav_url": "https://gen.daydream.live/v1/songs/sng_4hT2kq9XbV1nLm0pQe3rZa/1.wav"
    }
  ]
}

Another account's song answers 404.

List your songs

GET /v1/songs?limit=20&cursor=…

Newest first. limit is 1 to 100 (default 20). Pass the next_cursor you got back for the next page; it's null on the last one.

{ "songs": [ … ], "next_cursor": "eyJ0IjoxNzYw…" }

Usage

GET /v1/usage

{ "plan": "songs", "limit": 1000, "used": 212, "resets_at": "2026-11-01T00:00:00Z" }

plan is one of free, songs, pro, max, internal. limit is null when it's unlimited.

Audio links

/v1/songs/{id}/{n}.mp3 and /v1/songs/{id}/{n}.wav redirect to the file. They need no key and they don't expire, so you can store them and load them straight from a game engine or an <audio> tag. Anyone with a link can download that file. Follow redirects (curl -L).

MP3 is 192 kbps, WAV is 16-bit; both are stereo at 48 kHz.

Errors

Every error is JSON with a code to branch on and a sentence to show:

{
  "error": "limit",
  "message": "You've made all 10 of this month's songs.",
  "limit": 10,
  "used": 10,
  "plan": "free",
  "upgrade_url": "https://gen.daydream.live/pricing"
}
StatuserrorWhen
400invalidA field is wrong; the message names it.
401unauthorizedNo key, or a key that doesn't work.
402limitThis month's songs are used up. Comes with limit, used, plan and upgrade_url.
404not_foundNo such song on this account.
422prompt_rejectedThe prompt names an artist. Describe the sound instead.
429too_manyThree of your songs are already in line or being made. Wait for one to finish.
503unavailableThe generator is down for a moment. Try again shortly.

How fast

Songs are made one after another on a dedicated GPU: a song takes a few seconds once it's next, and a busy moment adds a short wait in line (position tells you where you are). Poll every 2 seconds; there's no need to poll faster. You can have up to three songs in line or being made at once.

Examples

curl

API=https://gen.daydream.live/v1
AUTH="Authorization: Bearer $DAYDREAM_API_KEY"

ID=$(curl -s $API/songs -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"prompt": "a tense boss fight with taiko drums and brass", "variations": 2}' | jq -r .id)

while :; do
  STATUS=$(curl -s $API/songs/$ID -H "$AUTH" | jq -r .status)
  [ "$STATUS" = done ] || [ "$STATUS" = failed ] && break
  sleep 2
done

curl -sL $API/songs/$ID/1.mp3 -o boss-1.mp3
curl -sL $API/songs/$ID/2.mp3 -o boss-2.mp3

JavaScript

Node 18 or later, or any runtime with fetch. Keep the key on the server.

const API = "https://gen.daydream.live/v1";
const KEY = process.env.DAYDREAM_API_KEY;

async function api(path, init = {}) {
  const r = await fetch(API + path, {
    ...init,
    headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
  });
  const body = await r.json();
  if (!r.ok) throw new Error(`${body.error}: ${body.message}`);
  return body;
}

let song = await api("/songs", {
  method: "POST",
  body: JSON.stringify({ prompt: "an open-world exploration theme with acoustic guitar", loop: true }),
});
while (song.status === "queued" || song.status === "rendering") {
  await new Promise((r) => setTimeout(r, 2000));
  song = await api(`/songs/${song.id}`);
}
if (song.status === "failed") throw new Error(song.error.message);
console.log(song.takes[0].mp3_url);

Python

import os, time, requests

API = "https://gen.daydream.live/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['DAYDREAM_API_KEY']}"}

r = requests.post(f"{API}/songs", headers=HEADERS, json={"prompt": "an upbeat 8-bit chiptune level theme", "loop": True})
r.raise_for_status()
song = r.json()

while song["status"] in ("queued", "rendering"):
    time.sleep(2)
    r = requests.get(f"{API}/songs/{song['id']}", headers=HEADERS)
    r.raise_for_status()
    song = r.json()

if song["status"] == "failed":
    raise RuntimeError(song["error"]["message"])

with open("level.mp3", "wb") as f:
    f.write(requests.get(song["takes"][0]["mp3_url"]).content)

Unity (C#)

A component that makes a song and plays it on loop. Use it in the editor or a tool; don't ship your key in a build.

using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

public class GenerateMusic : MonoBehaviour
{
    const string Api = "https://gen.daydream.live/v1";
    [SerializeField] string apiKey;
    [SerializeField] string prompt = "a calm village theme with flute and harp";
    [SerializeField] AudioSource source;

    [System.Serializable] class Create { public string prompt; public bool loop; }
    [System.Serializable] class Take { public int n; public float duration; public string mp3_url; public string wav_url; }
    [System.Serializable] class Song { public string id; public string status; public Take[] takes; }

    IEnumerator Start()
    {
        Song song = null;
        var body = Encoding.UTF8.GetBytes(JsonUtility.ToJson(new Create { prompt = prompt, loop = true }));
        using (var req = new UnityWebRequest(Api + "/songs", "POST"))
        {
            req.uploadHandler = new UploadHandlerRaw(body);
            req.downloadHandler = new DownloadHandlerBuffer();
            req.SetRequestHeader("Content-Type", "application/json");
            req.SetRequestHeader("Authorization", "Bearer " + apiKey);
            yield return req.SendWebRequest();
            if (req.result != UnityWebRequest.Result.Success) { Debug.LogError(req.downloadHandler.text); yield break; }
            song = JsonUtility.FromJson<Song>(req.downloadHandler.text);
        }

        while (song.status == "queued" || song.status == "rendering")
        {
            yield return new WaitForSeconds(2);
            using (var req = UnityWebRequest.Get(Api + "/songs/" + song.id))
            {
                req.SetRequestHeader("Authorization", "Bearer " + apiKey);
                yield return req.SendWebRequest();
                if (req.result != UnityWebRequest.Result.Success) { Debug.LogError(req.downloadHandler.text); yield break; }
                song = JsonUtility.FromJson<Song>(req.downloadHandler.text);
            }
        }
        if (song.status != "done") { Debug.LogError("The song didn't finish."); yield break; }

        using (var req = UnityWebRequestMultimedia.GetAudioClip(song.takes[0].mp3_url, AudioType.MPEG))
        {
            yield return req.SendWebRequest();
            if (req.result != UnityWebRequest.Result.Success) { Debug.LogError(req.error); yield break; }
            source.clip = DownloadHandlerAudioClip.GetContent(req);
            source.loop = true;
            source.Play();
        }
    }
}

Godot 4 (GDScript)

Attach to a node with an AudioStreamPlayer child. As with Unity, keep the key out of exported builds.

extends Node

const API := "https://gen.daydream.live/v1"
@export var api_key := ""
@export var prompt := "a calm village theme with flute and harp"
@onready var player: AudioStreamPlayer = $AudioStreamPlayer

func _ready() -> void:
	var song: Dictionary = await _call("/songs", HTTPClient.METHOD_POST, {"prompt": prompt, "loop": true})
	while song.get("status") in ["queued", "rendering"]:
		await get_tree().create_timer(2.0).timeout
		song = await _call("/songs/%s" % song["id"])
	if song.get("status") != "done":
		push_error("The song didn't finish: %s" % song)
		return
	var stream := AudioStreamMP3.new()
	stream.data = await _download(song["takes"][0]["mp3_url"])
	stream.loop = true
	player.stream = stream
	player.play()

func _call(path: String, method := HTTPClient.METHOD_GET, body = null) -> Dictionary:
	var http := HTTPRequest.new()
	add_child(http)
	var headers := PackedStringArray(["Authorization: Bearer %s" % api_key, "Content-Type: application/json"])
	http.request(API + path, headers, method, JSON.stringify(body) if body != null else "")
	var res: Array = await http.request_completed
	http.queue_free()
	return JSON.parse_string(res[3].get_string_from_utf8())

func _download(url: String) -> PackedByteArray:
	var http := HTTPRequest.new()
	add_child(http)
	http.request(url)
	var res: Array = await http.request_completed
	http.queue_free()
	return res[3]

More