How to Generate Game Sound Effects with an API (Python and JavaScript)
November 4, 2026 · 7 min read
Clicking through a web app is fine for ten sounds. When you need fifty placeholder effects for a greybox level, want a menu in your engine that generates audio, or keep a sound list in your repo, you want to generate sound effects from code. This guide shows the whole flow with the SFX Loom sound effects API, in Python and JavaScript.
The flow is three requests:
POST /api/v1/generationsstarts generating a sound from your prompt.GET /api/v1/generations/{id}tells you when it’s done (usually 5–30 seconds).GET /api/v1/sounds/{id}/download?format=wavgives you the file.
1. Create an API key
Sign in, open API in the app and click Create key. The full key starts with sfxl_ and is shown only once, so copy it straight into an environment variable:
export SFXLOOM_API_KEY="sfxl_..."The key spends your credits, so treat it like a password. Keep it on your machine, your build server or your backend. Never put it in a game build, a website or a mobile app: anyone can pull strings out of a shipped binary. Generate the sounds during development and ship the audio files.
2. Start a generation
Send a prompt, an optional model, model settings and how many takes you want (1–4):
import os
import requests
API = "https://sfxloom.com/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['SFXLOOM_API_KEY']}"
res = session.post(f"{API}/generations", json={
"model": "elevenlabs/sound-effects-v2",
"prompt": "Sword being drawn from a metal sheath, sharp metallic slide, "
"clean ringing tone at the end, close-up, no music, no background noise",
"params": {"duration": 2},
"variations": 2,
})
gen = res.json()
print(res.status_code, gen["id"], gen["status"], gen["credits"])The response is 202 Accepted with the generation still processing. At this point the full cost is reserved from your balance and shown in credits.reserved. If your balance is too low you get 402 insufficient_credits and nothing is charged.
Settings are strict on purpose: an unknown parameter, a value out of range or a duration off the slider step (the default model uses 0.5-second steps from 0.5 to 22 seconds) returns 400 invalid_params instead of being silently changed. GET /api/v1/models lists every model with its parameters and prices.
3. Poll until it’s done
Ask for the generation every few seconds. Each call also moves it forward: finished takes are saved to your library and, once every take is done, credits are settled.
import time
while gen["status"] in ("queued", "processing"):
time.sleep(3)
gen = session.get(f"{API}/generations/{gen['id']}").json()
print(gen["status"], gen["credits"])
# completed {'reserved': 2, 'charged': 2, 'refunded': 0}completed means at least one take succeeded; failed means none did. Every take that fails is refunded automatically, so you only pay for sounds you actually get. If your script crashes mid-way, nothing is lost: the generation still finishes and appears in your library, and unfinished work is refunded within 15 minutes.
4. Download as WAV
Each completed take has a sound_id. Ask for the format your engine wants: wav (16-bit PCM, best for short effects), ogg (small, great for loops) or mp3. Not sure which? WAV vs OGG vs MP3 explains the trade-offs.
for i, take in enumerate(gen["variations"], start=1):
if take["status"] != "completed":
continue
audio = session.get(
f"{API}/sounds/{take['sound_id']}/download",
params={"format": "wav"},
)
audio.raise_for_status()
with open(f"sword_draw_{i}.wav", "wb") as f:
f.write(audio.content)When the requested format is the one stored, the endpoint answers with a redirect to a short-lived signed file URL. Python requests and fetch follow it for you; with curl add -L.
The same thing in JavaScript
Node 18 or newer has fetch built in, so there’s nothing to install:
import { writeFile } from "node:fs/promises";
const API = "https://sfxloom.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.SFXLOOM_API_KEY}` };
async function call(path, init = {}) {
const res = await fetch(API + path, { ...init, headers: { ...headers, ...init.headers } });
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${res.status} ${error.code}: ${error.message}`);
}
return res;
}
let gen = await (
await call("/generations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
prompt: "Magic fireball spell cast, whoosh building up then fiery burst, fantasy game, no music",
params: { duration: 3 },
variations: 2,
}),
})
).json();
while (gen.status === "queued" || gen.status === "processing") {
await new Promise((r) => setTimeout(r, 3000));
gen = await (await call(`/generations/${gen.id}`)).json();
}
let i = 0;
for (const take of gen.variations.filter((v) => v.status === "completed")) {
const audio = await call(`/sounds/${take.sound_id}/download?format=wav`);
await writeFile(`fireball_${++i}.wav`, Buffer.from(await audio.arrayBuffer()));
}Handle errors properly
Every error has the same shape, { "error": { "code": "...", "message": "..." } }, so you can branch on the stable code:
402 insufficient_credits: nothing was charged. Top up and try again.429 rate_limitedorkey_rate_limited: wait for the number of seconds in theRetry-Afterheader, then retry. A rejected request is never charged.400 prompt_blocked: the prompt isn’t allowed (for example imitating a real person’s voice). Rewrite it.500 internal: safe to retryGETrequests.
One rule matters for your wallet: if a POST /generations times out on the network, don’t blindly send it again. The first request may have started (and reserved credits for) a generation. Check your library or recent generations first.
Prompts still matter
The API uses the same models as the web app, so the same prompt rules apply: name the source, the action, the material and the distance, and add “no music, no background noise”. The prompt writing guide has templates for every category, and the sound effects library has prompts that already work.
What to build next
- Generate a whole sound list from a CSV file: batch-generate sound effects with a script.
- Generate sounds without leaving your engine: a Unity editor window for the API.
- Read the full reference, prices and limits in the API documentation.
More guides