Guía

Masterizar audio mediante una API: curl, Python, Node, lotes y MCP

La API de Jam Jam masteriza un archivo de audio en el servidor con los mismos ajustes que la herramienta gratuita del navegador. Subes un archivo, eliges un preajuste o envías tus propios ajustes, sigues el trabajo y descargas un WAV. Esta guía da todo el recorrido en curl, Python y Node, el procesado por lotes, la gestión de errores y el servidor MCP para asistentes.

Masterizar una canción →

Herramienta asociada · Mastering de audio gratis, en tu navegador

Qué hace la API

La familia /mastering de la API REST de Jam Jam procesa un archivo de audio con un preajuste: equilibra el tono, calma las sibilancias, regula la anchura estéreo y lleva el nivel a un objetivo de volumen (streaming, Apple Music, Deezer, pódcast o club), con los ajustes de la herramienta web en jam-jam.org/app/mastering. El contrato OpenAPI 3.1 está en jam-jam.org/api/v1/openapi.json y la referencia en jam-jam.org/developers. Un archivo pesa como máximo 200 MB y dura como máximo 10 minutos, en mono o estéreo (a partir de dos canales se usan los dos primeros), y se procesa a 48 kHz. La salida es un WAV de 16 bits (wav-pcm16, por defecto) o de 32 bits en coma flotante (wav-f32); la API no ofrece 24 bits. El archivo de origen se borra en cuanto se decodifica y el resultado se conserva 24 horas. Un procesado en el servidor es reproducible (mismo archivo, mismos ajustes, mismo engineVersion), pero no se garantiza idéntico bit a bit a la exportación del navegador.

Masterizar una canción →

Conseguir una clave y comprobar tu acceso

Crea una cuenta en jam-jam.org, abre Ajustes y luego Claves de API (jam-jam.org/app/prefs/api-keys) y crea una clave con los permisos mastering:read y mastering:write. La clave empieza por jj_live_, solo se muestra una vez, y una cuenta puede tener cinco. Guárdala en la variable de entorno JAM_JAM_API_KEY, nunca en un repositorio ni en una línea de comandos compartida. El procesado de un archivo por la API (POST /mastering/jobs) está abierto a cualquier cuenta: 3 procesados por semana ISO con una cuenta gratuita, en el mismo contador que la herramienta web, y sin tope con Premium. Leer el contrato y listar o guardar preajustes también está abierto a cualquier cuenta.

Leer el contrato en vivo

GET /mastering/capabilities no necesita clave. Devuelve la versión del motor, el rango y el paso de cada ajuste, los objetivos de volumen, los preajustes integrados y los límites, y con una clave añade renderAllowed y el saldo de tu contador. Léelo en lugar de fijar los límites en el código. Cinco preajustes integrados son de solo lectura y se usan como preset=builtin:<id>: builtin:balanced, builtin:warm, builtin:bright, builtin:punchy y builtin:crushed. También puedes guardar hasta 50 preajustes propios (con un nombre de 60 caracteres como máximo) con POST /mastering/presets y llamarlos por su identificador.

Leer el contrato (no hace falta clave)

curl https://jam-jam.org/api/v1/mastering/capabilities

Procesar un archivo con curl

El recorrido es el de todos los trabajos de Jam Jam: un POST que responde 202, consultas hasta el final y luego la descarga. La cabecera Idempotency-Key (de 16 a 80 caracteres entre A-Z, a-z, 0-9, _ y -) es obligatoria en cada escritura: repetir la misma clave con el mismo cuerpo devuelve el mismo trabajo sin un segundo cobro. El trabajo pasa por queued, decoding, analyzing y rendering, y termina como done, failed, cancelled o expired; una vez terminado lleva un report con el volumen integrado (LUFS) y el pico real (dBTP) antes y después. Una cuenta tiene un procesado activo y tres en espera como máximo. El repositorio de ejemplos incluye los mismos pasos como scripts numerados, de curl/09-mastering-capabilities.sh a curl/14-mastering-delete.sh.

Procesar con un preajuste integrado, seguir el trabajo y descargar el WAV

# 1. Upload the file with a built-in preset (Idempotency-Key is required)
curl -X POST https://jam-jam.org/api/v1/mastering/jobs \
  -H "Authorization: Bearer $JAM_JAM_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F [email protected] -F preset=builtin:warm -F format=wav-pcm16
# The 202 answer carries the job "id": JOB_ID=<that id>

# 2. Follow the job, honouring Retry-After, until "status" is "done"
curl https://jam-jam.org/api/v1/mastering/jobs/$JOB_ID \
  -H "Authorization: Bearer $JAM_JAM_API_KEY"

# 3. Download the mastered WAV
curl -o mix-master.wav https://jam-jam.org/api/v1/mastering/jobs/$JOB_ID/result \
  -H "Authorization: Bearer $JAM_JAM_API_KEY"

Python y Node

Estos dos fragmentos condensan python/mastering_lib.py y javascript/mastering-lib.mjs del repositorio de ejemplos github.com/titouannwtt/jam-jam-api-examples (licencia MIT): Python 3.10 o posterior con requests, Node 20 o posterior sin dependencias. Los scripts completos añaden un mensaje legible para cada código HTTP y se ejecutan con python mastering.py master mix.wav --preset builtin:warm o node mastering.mjs master mix.wav --preset builtin:warm.

Python (3.10 o posterior, requests)

import os, time, uuid, requests

API = "https://jam-jam.org/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['JAM_JAM_API_KEY']}"}
FINAL = ("done", "failed", "cancelled", "expired")

# 1. Upload the file with a built-in preset. Idempotency-Key is required.
with open("mix.wav", "rb") as audio:
    res = requests.post(
        f"{API}/mastering/jobs",
        headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
        data={"preset": "builtin:warm", "format": "wav-pcm16"},
        files={"file": ("mix.wav", audio)},
    )
res.raise_for_status()
job = res.json()

# 2. Poll, waiting as long as the server asks.
while job["status"] not in FINAL:
    time.sleep(int(res.headers.get("Retry-After") or 2))
    res = requests.get(f"{API}/mastering/jobs/{job['id']}", headers=HEADERS)
    res.raise_for_status()
    job = res.json()
if job["status"] != "done":
    raise SystemExit(f"mastering {job['status']}: {job.get('error')}")

before, after = job["report"]["before"], job["report"]["after"]
print(f"LUFS {before['integratedLufs']} -> {after['integratedLufs']}")

# 3. Download the mastered WAV.
audio = requests.get(f"{API}/mastering/jobs/{job['id']}/result", headers=HEADERS)
audio.raise_for_status()
with open("mix-master.wav", "wb") as out:
    out.write(audio.content)

Node (20 o posterior, sin dependencias)

import { openAsBlob } from 'node:fs';
import { writeFile } from 'node:fs/promises';

const API = 'https://jam-jam.org/api/v1';
const headers = { Authorization: `Bearer ${process.env.JAM_JAM_API_KEY}` };
const FINAL = ['done', 'failed', 'cancelled', 'expired'];

// 1. Upload the file with a built-in preset. Idempotency-Key is required.
const body = new FormData();
body.append('file', await openAsBlob('mix.wav'), 'mix.wav');
body.append('preset', 'builtin:warm');
body.append('format', 'wav-pcm16');
let res = await fetch(`${API}/mastering/jobs`, {
  method: 'POST',
  headers: { ...headers, 'Idempotency-Key': crypto.randomUUID() },
  body,
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
let job = await res.json();

// 2. Poll, waiting as long as the server asks.
while (!FINAL.includes(job.status)) {
  await new Promise((r) => setTimeout(r, (Number(res.headers.get('retry-after')) || 2) * 1000));
  res = await fetch(`${API}/mastering/jobs/${job.id}`, { headers });
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  job = await res.json();
}
if (job.status !== 'done') throw new Error(`mastering ${job.status}: ${JSON.stringify(job.error)}`);

const { before, after } = job.report;
console.log(`LUFS ${before.integratedLufs} -> ${after.integratedLufs}`);

// 3. Download the mastered WAV.
res = await fetch(`${API}/mastering/jobs/${job.id}/result`, { headers });
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
await writeFile('mix-master.wav', Buffer.from(await res.arrayBuffer()));

Tus propios ajustes

En lugar de un preajuste, envía los ajustes en JSON en el campo settings: exactamente uno de los dos, preset o settings. El formato (MasteringSettingsV1) contiene ocho módulos, cada uno con un value y un indicador enabled, un objetivo de volumen (streaming, apple, deezer, podcast o club) y normalize. Los ajustes de tono van en decibelios y los demás en porcentaje, hasta 150; un valor fuera de su rango o de su paso responde 422 invalid-settings con una entrada por problema. Para reutilizar un conjunto de ajustes, guárdalo con POST /mastering/presets y pasa su identificador en preset. Los ajustes se copian al subir el archivo: modificar el preajuste después no cambia un trabajo ya iniciado.

Enviar tus propios ajustes

{
  "modules": {
    "autoEq":   { "value": 50, "enabled": true },
    "lows":     { "value": 2, "enabled": true },
    "mids":     { "value": -0.5, "enabled": true },
    "highs":    { "value": -1.5, "enabled": true },
    "deEss":    { "value": 40, "enabled": true },
    "width":    { "value": 10, "enabled": true },
    "loudness": { "value": 45, "enabled": true },
    "destruct": { "value": 0, "enabled": false }
  },
  "target": "streaming",
  "normalize": false
}

Enviar tus propios ajustes

curl -X POST https://jam-jam.org/api/v1/mastering/jobs \
  -H "Authorization: Bearer $JAM_JAM_API_KEY" -H "Idempotency-Key: $(uuidgen)" \
  -F [email protected] -F "settings=<samples/mastering-settings.json" -F format=wav-pcm16

Masterizar una carpeta entera por lotes

El repositorio contiene dos scripts de lotes, python/mastering_batch.py y javascript/mastering-batch.mjs, que masterizan una carpeta con un preajuste, un archivo detrás de otro. Conviene copiar tres decisiones. Los archivos se envían uno a uno, porque una cuenta admite un procesado activo y tres en espera. Se omite un archivo cuyo nombre-master.wav ya existe, así que puedes volver a lanzarlo tras una interrupción. Ante un 429 con una espera corta (cinco minutos como máximo), el script espera Retry-After y repite el mismo archivo con la misma clave de idempotencia, y se detiene ante un 403 o un 429 largo, porque los archivos siguientes fallarían igual.

Masterizar una carpeta, un archivo cada vez

python mastering_batch.py ~/Music/mixes --preset builtin:balanced --out masters
node mastering-batch.mjs ~/Music/mixes --preset builtin:balanced --out masters

Errores y cuotas

Cada error es un application/problem+json con un code estable que puedes comprobar, y las respuestas de procesado llevan las cabeceras X-Mastering-Quota-Limit, X-Mastering-Quota-Remaining y X-Mastering-Quota-Reset. Las cuentas Premium no tienen tope de procesados. En una cuenta gratuita, un 429 con el código quota-exhausted indica que se agotaron los procesados de la semana; cualquier otro 429 indica un límite de frecuencia o una cola ocupada. Un procesado fallido o cancelado no se cuenta. El procesado de un archivo por la API (POST /mastering/jobs) está abierto a cualquier cuenta: 3 procesados por semana ISO con una cuenta gratuita, en el mismo contador que la herramienta web, y sin tope con Premium. Leer el contrato y listar o guardar preajustes también está abierto a cualquier cuenta.

Errores del mastering y qué hacer
EstadoCódigoSignificado
401Clave ausente o no válida.
403insufficient-scopeLa clave no tiene el permiso mastering:read o mastering:write.
403premium-requiredEl procesado no está abierto a tu plan (consulta renderAllowed en GET /mastering/capabilities).
409not-readyResultado pedido antes de que termine el procesado.
410expiredHan pasado las 24 horas: vuelve a procesar.
413, 415, 422Archivo demasiado grande, formato no admitido, audio de más de 10 minutos o ajustes no válidos (lee errors[]).
429rate-limitedDemasiadas peticiones, o un procesado ya en curso y tres en espera (client-quota), o cola llena (queue-full): espera Retry-After segundos y no entres en bucle.

El servidor MCP para asistentes

El servidor MCP oficial @jam-jam/convert-mcp ofrece el Mastering a Claude Desktop, Claude Code, Cursor y otros clientes de Model Context Protocol, y solo muestra las herramientas que permiten los permisos de tu clave. Seis herramientas cubren el Mastering: jj_mastering_capabilities (sin permiso), jj_list_mastering_presets, jj_create_mastering_preset, jj_master_audio, jj_mastering_get_job y jj_mastering_cancel_job. jj_master_audio sube un archivo local con un preajuste o con ajustes en línea y, con maxWaitMs, espera y descarga el resultado. Después puedes pedirle a tu asistente que masterice un archivo con el preajuste warm y te diga el volumen antes y después. Pon la clave en el entorno, nunca en una línea de comandos.

Configuración de un cliente MCP

{
  "mcpServers": {
    "jam-jam": {
      "command": "npx",
      "args": ["-y", "@jam-jam/convert-mcp"],
      "env": { "JAM_JAM_API_KEY": "jj_live_..." }
    }
  }
}

Para entender qué hacen los ajustes y qué volumen buscar, lee nuestra guía para masterizar una canción gratis.

Preguntas frecuentes sobre la API de mastering

¿La API de mastering de Jam Jam es gratuita?

Sí. Con una cuenta gratuita, POST /mastering/jobs procesa 3 archivos por semana ISO, en el mismo contador que la herramienta web; un procesado fallido o cancelado se devuelve. Premium quita el tope. Leer el contrato en vivo y gestionar tus preajustes no cuesta nada.

¿Cuáles son los límites de archivo?

Como máximo 200 MB y 10 minutos, en mono o estéreo. El resultado es un WAV a 48 kHz, de 16 bits, de 24 bits o de 32 bits en coma flotante, conservado 24 horas.

¿El resultado es idéntico al del navegador?

Es reproducible en el servidor (mismo archivo, mismos ajustes, mismo engineVersion), pero no se garantiza idéntico bit a bit a la exportación del navegador. Los ajustes son los mismos.

¿Puedo enviar varios archivos a la vez?

Una cuenta tiene un procesado activo y tres en espera. Para una carpeta, envía los archivos uno a uno con los scripts de lotes del repositorio de ejemplos.

¿Cómo se usa con un asistente de IA?

Con el servidor MCP @jam-jam/convert-mcp: la herramienta jj_master_audio masteriza un archivo local y jj_mastering_get_job lee el volumen antes y después.

El mismo motor se puede probar gratis en tu navegador, con tu archivo en tu dispositivo.