Ir al contenido
HILLS API v1 Acceso anticipado

Guías

Errores

El formato de los errores, cada estado y código que responde la API, qué errores conviene reintentar y un gestor de errores en Node listo para copiar.

Actualizado el

Cuando una solicitud falla, la API responde con un estado 4xx o 5xx y un cuerpo JSON con un code estable. Decide según code. El texto de error es para personas y puede cambiar.

El formato

{
  "error": "This API key doesn't have the earnings:read scope.",
  "code": "insufficient_scope",
  "scope": "earnings:read"
}
Campo Siempre Significado
error Sí Qué ha fallado, en palabras. Se puede registrar o mostrar a un operador sin problema.
code Sí Un código estable. Consulta las tablas de abajo.
field Con invalid El parámetro o campo del cuerpo que falla.
scope Con insufficient_scope El ámbito que necesita la clave.

Algunos errores añaden sus propios campos. Por ejemplo, 409 upload_incomplete enumera las partes missing y wrong_size.

Errores que puede responder cualquier endpoint

Estado code Significado ¿Reintentar?
400 invalid Un parámetro es incorrecto. field indica cuál. No. Corrige la solicitud.
401 unauthenticated Falta la cabecera Authorization: Bearer. No
401 invalid_key La clave no existe. No
401 key_revoked La clave se revocó. Crea una nueva. No
401 key_expired La clave ha caducado. Crea una nueva. No
401 test_keys_retired Una clave hm_test_, retirada el 12 de octubre de 2026. Usa una clave hm_live_. No
403 insufficient_scope A la clave le falta el ámbito que necesita este endpoint. scope indica cuál. No
403 account_inactive Tu cuenta no está activa. No
403 api_not_in_plan Tu plan no incluye la API. Se incluye en Enterprise y Custom. No
404 not_found El endpoint no existe, o el recurso no es tuyo. No
429 rate_limited Has superado tu límite por minuto con esta clave. Sí, tras los segundos de Retry-After
500 server_error Algo ha fallado por nuestra parte. Sí, con espera progresiva

404 not_found cubre tanto «no existe» como «pertenece a otra cuenta». La API nunca te revela que existe un lanzamiento de otra persona.

Errores de endpoints concretos

Estado code Dónde Significado
409 exists POST /members/invite Ya hay una cuenta con este correo.
413 too_large POST /ddex/validate Supera el tamaño que admite una prueba. Entrégalo con POST /ddex.
413 too_large POST /ddex Más de 20 GB (cuerpo en bruto) o de 512 MB (multipart). Usa una subida directa.
429 busy POST /ddex/validate Demasiadas pruebas a la vez. Vuelve a intentarlo en breve.
409 upload_incomplete POST /ddex/uploads/{id}/commit Faltan partes o su tamaño es incorrecto. Súbelas y vuelve a confirmar.
409 already_committed Subidas directas Ya se confirmó. status_url apunta a la entrega.
409 commit_in_progress POST /ddex/uploads/{id}/commit Hay otra confirmación de esta subida en curso.
400 invalid_url POST /webhooks, PATCH /webhooks/{id} No es una URL https pública en el puerto 443.
409 too_many POST /webhooks Ya tienes 20 endpoints.
409 endpoint_disabled Prueba y reintento de webhooks El endpoint está desactivado. Actívalo primero.

Cada página de la referencia enumera los errores de cada endpoint. Ámbitos y errores recoge los comunes.

Errores de validación

Un 400 invalid indica el primer problema que encontró:

{
  "error": "updated_since is an ISO date or time.",
  "code": "invalid",
  "field": "updated_since"
}

Solo se informa de un campo cada vez. Corrígelo y vuelve a enviar. Si construyes un formulario sobre la API, muestra error junto al campo indicado en field.

Con los archivos DDEX es distinto. Un lote DDEX con problemas no da un 400. La prueba responde 200 con cada comprobación y un veredicto, y una entrega responde 202 e informa de los problemas por lanzamiento. Consulta Entrega DDEX.

Qué reintentar

  • Reintenta los 429 y 5xx, y los errores de red, como los tiempos de espera agotados y las conexiones restablecidas.
  • No reintentes el resto de 4xx. La misma solicitud recibe la misma respuesta. Corrige antes la solicitud, la clave o sus ámbitos.

Para un 429, espera los segundos que indique Retry-After. Para un 5xx, espera más tras cada intento (1 s, 2 s, 4 s…) y desiste tras unos pocos. Consulta Límites de solicitudes.

Las lecturas se pueden reintentar sin riesgo. Piénsalo antes de reintentar una escritura. Si reintentas un POST /ddex tras perder la respuesta, el lote puede quedar en cola dos veces. Búscalo antes en GET /ddex.

Un gestor de errores en Node

export class HillsError extends Error {
  constructor(status, body, headers) {
    super(body.error ?? `HTTP ${status}`);
    this.status = status;
    this.code = body.code;
    this.field = body.field;
    this.scope = body.scope;
    this.retryAfter = Number(headers.get("Retry-After")) || null;
  }
}

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function hills(path, init = {}, tries = 4) {
  for (let i = 1; ; i++) {
    const res = await fetch("https://api.hillsmusic.com/v1" + path, {
      ...init,
      headers: { ...init.headers, Authorization: `Bearer ${process.env.HILLS_API_KEY}` },
    });
    const body = await res.json().catch(() => ({}));
    if (res.ok) return body;
    const err = new HillsError(res.status, body, res.headers);
    const retryable = res.status === 429 || res.status >= 500;
    if (!retryable || i >= tries) throw err;
    await sleep(err.retryAfter ? err.retryAfter * 1000 : 1000 * 2 ** (i - 1));
  }
}

try {
  await hills("/earnings");
} catch (err) {
  if (err.code === "insufficient_scope") console.error(`Add ${err.scope} to this key.`);
  else if (err.code === "api_not_in_plan") console.error("The plan doesn't include the API.");
  else throw err;
}

Con curl, añade -w '%{http_code}' para ver el estado, o -i para ver las cabeceras:

curl -i "https://api.hillsmusic.com/v1/releases/999999" \
  -H "Authorization: Bearer $HILLS_API_KEY"
# HTTP/2 404
# {"error":"…","code":"not_found"}

¿Listo para integrar?

Solicita acceso a la API y te respondemos en 1 a 3 días hábiles.