Music Generation API

Introduction

This API provides AI-powered music generation from text descriptions. Create custom songs, background music, and audio tracks by describing what you want in natural language.

Try the Interactive Playground →
Important: Music generation is processed asynchronously. After submitting a generation request, you'll receive a job ID that you can use to poll for results. Each generation costs approximately $0.03 per song.

Example Integrations

Authentication

All API requests require authentication using a Bearer token. Include your API key in the Authorization header of every request:

Authorization: Bearer YOUR_API_KEY
Security Note: Never expose your API key in client-side code. Always make requests from your server.

Available Models

The API provides two music generation models with different capabilities:

Music 1.5

Model ID: music-1.5

First-generation music synthesis model. Suitable for general-purpose music generation with good quality.

Fast Generation Multiple Genres Lyrics Support

Music 2.0

Model ID: music-2.0

Latest model with improved audio quality, better adherence to prompts, and enhanced musical coherence. Recommended for production use.

High Quality Better Prompt Following Advanced Lyrics
Pricing: Both models use the same pricing: approximately $0.03 per generated song (typically 30-60 seconds in length).

Music Generation: POST /api/v1/generate

This endpoint creates a music generation job. The music is generated asynchronously, and you'll receive a job ID to poll for results.

Request

Send a POST request with a JSON body containing your music description and optional configuration.

Required Parameters

ParameterTypeDescription
promptstringText description of the music you want to generate

Optional Parameters

ParameterTypeDefaultDescription
modelstring"music-2.0"Model to use: "music-1.5" or "music-2.0"
lyricsstring""Optional lyrics for the song
audio_settings.sample_rateinteger44100Sample rate in Hz (8000-48000)
audio_settings.bitrateinteger256000Bit rate (64000-320000)
audio_settings.formatstring"mp3"Audio format: "mp3", "wav", or "flac"
response_formatstring"hex"Encoding: "hex", "base64", or "data_url"

Example Request

{
  "model": "music-2.0",
  "prompt": "upbeat electronic dance music with energetic drums and synthesizers",
  "lyrics": "Dancing through the night\nFeeling so alive\nLights are shining bright",
  "audio_settings": {
    "sample_rate": 44100,
    "bitrate": 256000,
    "format": "mp3"
  },
  "response_format": "base64"
}

Response

A successful request returns a job object with a unique job ID and polling information:

{
  "id": "job-1234567890abcdef1234567890abcdef",
  "object": "music.generation.job",
  "status": "pending",
  "created": 1699123456,
  "poll_url": "/api/v1/poll/job-1234567890abcdef1234567890abcdef",
  "processing_mode": "background"
}

Response Fields

FieldTypeDescription
idstringUnique job identifier for polling
statusstringCurrent job status: "pending", "processing", "completed", or "failed"
createdintegerUnix timestamp of job creation
poll_urlstringEndpoint to poll for job status and results
processing_modestring"background" or "synchronous" depending on server configuration

Polling for Results: GET /api/v1/poll/<job_id>

After creating a generation job, poll this endpoint to check the status and retrieve results when complete.

Request

Make a GET request to the poll URL provided in the generation response, or construct it manually:

GET /api/v1/poll/job-1234567890abcdef1234567890abcdef
Authorization: Bearer YOUR_API_KEY

Response - Job Pending/Processing

{
  "id": "job-1234567890abcdef1234567890abcdef",
  "object": "music.generation.job",
  "status": "processing",
  "created": 1699123456,
  "updated": 1699123461,
  "poll_interval": 5,
  "message": "Job is still processing. Please poll again."
}

Response - Job Completed

Warning: The job data will be automatically deleted after successful retrieval! This includes the audio files.
{
  "id": "job-1234567890abcdef1234567890abcdef",
  "object": "music.generation.job",
  "status": "completed",
  "created": 1699123456,
  "updated": 1699123490,
  "result": {
    "id": "music-gen-abcdef123456",
    "object": "music.generation",
    "created": 1699123490,
    "model": "music-2.0",
    "choices": [
      {
        "index": 0,
        "audio": {
          "data": "base64_encoded_audio_data_here...",
          "format": "mp3",
          "encoding": "base64"
        },
        "finish_reason": "completed"
      }
    ],
    "usage": {
      "estimated_cost": 0.03,
      "currency": "USD"
    }
  }
}

Response - Job Failed

{
  "id": "job-1234567890abcdef1234567890abcdef",
  "object": "music.generation.job",
  "status": "failed",
  "created": 1699123456,
  "updated": 1699123470,
  "error": {
    "message": "Generation failed due to invalid prompt",
    "type": "generation_error"
  }
}

Audio Formats

The API supports multiple audio formats and quality settings to suit different use cases.

MP3 Format

Compressed audio format ideal for streaming and storage efficiency. Recommended for most applications.

ParameterOptionsDescription
sample_rate8000, 16000, 22050, 24000, 32000, 44100, 48000Higher rates provide better quality (44100 recommended)
bitrate64000 - 320000Higher bitrates provide better quality (256000 recommended)

Example: High Quality MP3

{
  "audio_settings": {
    "format": "mp3",
    "sample_rate": 48000,
    "bitrate": 320000
  }
}

WAV Format

Uncompressed audio format for professional audio production and editing.

{
  "audio_settings": {
    "format": "wav",
    "sample_rate": 44100
  }
}

FLAC Format

Lossless compressed audio format. Provides perfect quality with smaller file sizes than WAV.

{
  "audio_settings": {
    "format": "flac",
    "sample_rate": 44100
  }
}

Sample Rate Recommendations

Sample RateUse Case
8000 HzTelephony, voice-only applications
16000 HzVoice-focused content, reduced file size
22050 HzBasic music quality, web streaming
44100 HzCD quality, recommended for most music (default)
48000 HzProfessional audio, video soundtracks

Response Formats

Control how the audio data is encoded in the API response using the response_format parameter.

Hex Encoding (Default)

Raw hexadecimal encoding of the audio binary data. Efficient for server-to-server communication.

{
  "response_format": "hex"
}

// Response
{
  "audio": {
    "data": "49443303000000000f...",
    "encoding": "hex"
  }
}

Base64 Encoding

Standard Base64 encoding. Compatible with most programming languages and easier to handle in JSON.

{
  "response_format": "base64"
}

// Response
{
  "audio": {
    "data": "SUQzAwAAAAAA...",
    "encoding": "base64"
  }
}

Data URL

Complete data URL with MIME type. Can be used directly in HTML audio elements or image tags.

{
  "response_format": "data_url"
}

// Response
{
  "audio": {
    "data": "data:audio/mp3;base64,SUQzAwAAAAAA...",
    "encoding": "data_url"
  }
}

Usage in HTML

<audio controls>
  <source src="data:audio/mp3;base64,SUQzAwAAAAAA..." type="audio/mpeg">
</audio>

Error Handling

When an error occurs, the API returns an appropriate HTTP status code and a JSON error object:

{
  "error": {
    "message": "Invalid API key provided",
    "type": "invalid_request_error",
    "code": null
  }
}

Common Error Codes

Status CodeError TypeDescription
400Bad RequestInvalid request format or parameters
401UnauthorizedMissing or invalid API key
402Payment RequiredInsufficient account balance
404Not FoundJob ID not found or expired
500Server ErrorInternal server error, try again later

Generation Errors

Errors during music generation are returned in the job result:

{
  "status": "failed",
  "error": {
    "message": "Prompt contains inappropriate content",
    "type": "content_policy_violation"
  }
}

Error Types

Error TypeDescription
invalid_request_errorRequest parameters are invalid or malformed
authentication_errorAPI key is missing, invalid, or expired
insufficient_balanceAccount balance is too low for the operation
generation_errorMusic generation process failed
content_policy_violationPrompt violates content policy
server_errorInternal server error occurred

Code Examples

Here are examples of how to use the API in different programming languages.

import requests
import time
import base64

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://music.demo.efficientstack.com/api/v1"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

def generate_music(prompt, lyrics=None, model="music-2.0"):
    """Create a music generation job"""
    payload = {
        "model": model,
        "prompt": prompt,
        "audio_settings": {
            "sample_rate": 44100,
            "bitrate": 256000,
            "format": "mp3"
        },
        "response_format": "base64"
    }
    
    if lyrics:
        payload["lyrics"] = lyrics
    
    response = requests.post(
        f"{BASE_URL}/generate",
        headers=headers,
        json=payload
    )
    
    if response.status_code != 200:
        raise Exception(f"Generation failed: {response.json()}")
    
    return response.json()

def poll_job(job_id, max_attempts=60, interval=5):
    """Poll for job completion"""
    for attempt in range(max_attempts):
        response = requests.get(
            f"{BASE_URL}/poll/{job_id}",
            headers={"Authorization": f"Bearer {API_KEY}"}
        )
        
        if response.status_code != 200:
            raise Exception(f"Polling failed: {response.json()}")
        
        data = response.json()
        status = data["status"]
        
        print(f"Attempt {attempt + 1}: Status = {status}")
        
        if status == "completed":
            return data["result"]
        elif status == "failed":
            raise Exception(f"Generation failed: {data['error']['message']}")
        
        time.sleep(interval)
    
    raise Exception("Job timed out")

def save_audio(audio_data, filename, encoding="base64"):
    """Save audio data to file"""
    if encoding == "base64":
        audio_bytes = base64.b64decode(audio_data)
    elif encoding == "hex":
        audio_bytes = bytes.fromhex(audio_data)
    else:
        raise ValueError(f"Unsupported encoding: {encoding}")
    
    with open(filename, "wb") as f:
        f.write(audio_bytes)
    
    print(f"Audio saved to {filename}")

# Example usage
if __name__ == "__main__":
    # Generate music
    prompt = "upbeat electronic dance music with energetic drums"
    lyrics = "Dancing through the night\nFeeling so alive"
    
    print("Creating music generation job...")
    job = generate_music(prompt, lyrics, model="music-2.0")
    job_id = job["id"]
    
    print(f"Job created: {job_id}")
    print("Polling for results...")
    
    # Poll for results
    result = poll_job(job_id)
    
    # Save audio
    audio_data = result["choices"][0]["audio"]["data"]
    encoding = result["choices"][0]["audio"]["encoding"]
    
    save_audio(audio_data, "generated_music.mp3", encoding)
    
    # Print usage info
    cost = result["usage"]["estimated_cost"]
    print(f"Estimated cost: ${cost}")
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://music.demo.efficientstack.com/api/v1";

const headers = {
  "Authorization": `Bearer ${API_KEY}`,
  "Content-Type": "application/json"
};

async function generateMusic(prompt, lyrics = null, model = "music-2.0") {
  const payload = {
    model: model,
    prompt: prompt,
    audio_settings: {
      sample_rate: 44100,
      bitrate: 256000,
      format: "mp3"
    },
    response_format: "base64"
  };
  
  if (lyrics) {
    payload.lyrics = lyrics;
  }
  
  const response = await fetch(`${BASE_URL}/generate`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(payload)
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Generation failed: ${error.error.message}`);
  }
  
  return await response.json();
}

async function pollJob(jobId, maxAttempts = 60, interval = 5000) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const response = await fetch(`${BASE_URL}/poll/${jobId}`, {
      headers: { "Authorization": `Bearer ${API_KEY}` }
    });
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Polling failed: ${error.error.message}`);
    }
    
    const data = await response.json();
    const status = data.status;
    
    console.log(`Attempt ${attempt + 1}: Status = ${status}`);
    
    if (status === "completed") {
      return data.result;
    } else if (status === "failed") {
      throw new Error(`Generation failed: ${data.error.message}`);
    }
    
    // Wait before next poll
    await new Promise(resolve => setTimeout(resolve, interval));
  }
  
  throw new Error("Job timed out");
}

function downloadAudio(audioData, filename, encoding = "base64") {
  let blob;
  
  if (encoding === "base64") {
    const binaryString = atob(audioData);
    const bytes = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    blob = new Blob([bytes], { type: "audio/mpeg" });
  } else if (encoding === "data_url") {
    // Extract base64 from data URL
    const base64 = audioData.split(',')[1];
    const binaryString = atob(base64);
    const bytes = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    blob = new Blob([bytes], { type: "audio/mpeg" });
  }
  
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  
  URL.revokeObjectURL(url);
  console.log(`Audio downloaded: ${filename}`);
}

// Example usage
async function main() {
  try {
    const prompt = "upbeat electronic dance music with energetic drums";
    const lyrics = "Dancing through the night\nFeeling so alive";
    
    console.log("Creating music generation job...");
    const job = await generateMusic(prompt, lyrics, "music-2.0");
    const jobId = job.id;
    
    console.log(`Job created: ${jobId}`);
    console.log("Polling for results...");
    
    const result = await pollJob(jobId);
    
    const audioData = result.choices[0].audio.data;
    const encoding = result.choices[0].audio.encoding;
    
    downloadAudio(audioData, "generated_music.mp3", encoding);
    
    const cost = result.usage.estimated_cost;
    console.log(`Estimated cost: $${cost}`);
    
  } catch (error) {
    console.error("Error:", error.message);
  }
}

main();
#!/bin/bash

API_KEY="YOUR_API_KEY"
BASE_URL="https://music.demo.efficientstack.com/api/v1"

# Create music generation job
echo "Creating music generation job..."
RESPONSE=$(curl -s -X POST "$BASE_URL/generate" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "music-2.0",
    "prompt": "upbeat electronic dance music with energetic drums",
    "lyrics": "Dancing through the night\nFeeling so alive",
    "audio_settings": {
      "sample_rate": 44100,
      "bitrate": 256000,
      "format": "mp3"
    },
    "response_format": "base64"
  }')

# Extract job ID
JOB_ID=$(echo $RESPONSE | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
echo "Job created: $JOB_ID"

# Poll for results
echo "Polling for results..."
MAX_ATTEMPTS=60
ATTEMPT=0

while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
  ATTEMPT=$((ATTEMPT + 1))
  
  POLL_RESPONSE=$(curl -s -X GET "$BASE_URL/poll/$JOB_ID" \
    -H "Authorization: Bearer $API_KEY")
  
  STATUS=$(echo $POLL_RESPONSE | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
  echo "Attempt $ATTEMPT: Status = $STATUS"
  
  if [ "$STATUS" = "completed" ]; then
    echo "Job completed!"
    
    # Extract audio data and save to file
    echo $POLL_RESPONSE | \
      grep -o '"data":"[^"]*"' | \
      head -1 | \
      cut -d'"' -f4 | \
      base64 -d > generated_music.mp3
    
    echo "Audio saved to generated_music.mp3"
    exit 0
  elif [ "$STATUS" = "failed" ]; then
    echo "Job failed!"
    echo $POLL_RESPONSE
    exit 1
  fi
  
  sleep 5
done

echo "Job timed out!"
exit 1
<?php

$apiKey = "YOUR_API_KEY";
$baseUrl = "https://music.demo.efficientstack.com/api/v1";

function generateMusic($apiKey, $baseUrl, $prompt, $lyrics = null, $model = "music-2.0") {
    $payload = [
        'model' => $model,
        'prompt' => $prompt,
        'audio_settings' => [
            'sample_rate' => 44100,
            'bitrate' => 256000,
            'format' => 'mp3'
        ],
        'response_format' => 'base64'
    ];
    
    if ($lyrics !== null) {
        $payload['lyrics'] = $lyrics;
    }
    
    $ch = curl_init("$baseUrl/generate");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Authorization: Bearer $apiKey",
        "Content-Type: application/json"
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode !== 200) {
        $error = json_decode($response, true);
        throw new Exception("Generation failed: " . $error['error']['message']);
    }
    
    return json_decode($response, true);
}

function pollJob($apiKey, $baseUrl, $jobId, $maxAttempts = 60, $interval = 5) {
    for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
        $ch = curl_init("$baseUrl/poll/" . urlencode($jobId));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Authorization: Bearer $apiKey"
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($httpCode !== 200) {
            $error = json_decode($response, true);
            throw new Exception("Polling failed: " . $error['error']['message']);
        }
        
        $data = json_decode($response, true);
        $status = $data['status'];
        
        echo "Attempt " . ($attempt + 1) . ": Status = $status\n";
        
        if ($status === 'completed') {
            return $data['result'];
        } else if ($status === 'failed') {
            throw new Exception("Generation failed: " . $data['error']['message']);
        }
        
        sleep($interval);
    }
    
    throw new Exception("Job timed out");
}

function saveAudio($audioData, $filename, $encoding = 'base64') {
    if ($encoding === 'base64') {
        $audioBytes = base64_decode($audioData);
    } else if ($encoding === 'hex') {
        $audioBytes = hex2bin($audioData);
    } else {
        throw new Exception("Unsupported encoding: $encoding");
    }
    
    file_put_contents($filename, $audioBytes);
    echo "Audio saved to $filename\n";
}

// Example usage
try {
    $prompt = "upbeat electronic dance music with energetic drums";
    $lyrics = "Dancing through the night\nFeeling so alive";
    
    echo "Creating music generation job...\n";
    $job = generateMusic($apiKey, $baseUrl, $prompt, $lyrics, "music-2.0");
    $jobId = $job['id'];
    
    echo "Job created: $jobId\n";
    echo "Polling for results...\n";
    
    $result = pollJob($apiKey, $baseUrl, $jobId);
    
    $audioData = $result['choices'][0]['audio']['data'];
    $encoding = $result['choices'][0]['audio']['encoding'];
    
    saveAudio($audioData, 'generated_music.mp3', $encoding);
    
    $cost = $result['usage']['estimated_cost'];
    echo "Estimated cost: \$$cost\n";
    
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

?>