Erros
O formato dos erros, cada status e código que a API responde, quais erros tentar de novo e um tratador de erros em Node pronto para copiar.
Atualizado em
Quando uma requisição falha, a API responde com um status 4xx ou 5xx e um corpo JSON com um code estável. Tome decisões com base em code. O texto de error é para pessoas e pode mudar.
O formato
{
"error": "This API key doesn't have the earnings:read scope.",
"code": "insufficient_scope",
"scope": "earnings:read"
}
| Campo | Sempre | Significado |
|---|---|---|
error |
Sim | O que deu errado, por extenso. Pode ser registrado em log ou mostrado a um operador. |
code |
Sim | Um código estável. Veja as tabelas abaixo. |
field |
Com invalid |
O parâmetro ou campo do corpo com problema. |
scope |
Com insufficient_scope |
O escopo de que a chave precisa. |
Alguns erros acrescentam campos próprios. Por exemplo, 409 upload_incomplete lista as partes em missing e wrong_size.
Erros que qualquer endpoint pode responder
| Status | code |
Significado | Tentar de novo? |
|---|---|---|---|
| 400 | invalid |
Um parâmetro está errado. field indica qual. |
Não. Corrija a requisição. |
| 401 | unauthenticated |
Falta o header Authorization: Bearer. |
Não |
| 401 | invalid_key |
A chave não existe. | Não |
| 401 | key_revoked |
A chave foi revogada. Crie uma nova. | Não |
| 401 | key_expired |
A chave expirou. Crie uma nova. | Não |
| 401 | test_keys_retired |
Uma chave hm_test_. Desativada em 12 de outubro de 2026. Use uma chave hm_live_. |
Não |
| 403 | insufficient_scope |
Falta à chave o escopo exigido por este endpoint. scope indica qual. |
Não |
| 403 | account_inactive |
Sua conta não está ativa. | Não |
| 403 | api_not_in_plan |
Seu plano não inclui a API. Ela vem com o Enterprise e o Custom. | Não |
| 404 | not_found |
Esse endpoint não existe, ou o recurso não é seu. | Não |
| 429 | rate_limited |
Acima do seu limite por minuto nesta chave. | Sim, após Retry-After segundos |
| 500 | server_error |
Algo deu errado do nosso lado. | Sim, com backoff |
404 not_found cobre tanto “não existe” quanto “pertence a outra conta”. A API nunca revela que o lançamento de outra pessoa existe.
Erros de endpoints específicos
| Status | code |
Onde | Significado |
|---|---|---|---|
| 409 | exists |
POST /members/invite |
Já existe uma conta com este e-mail. |
| 413 | too_large |
POST /ddex/validate |
Maior do que um teste aceita. Entregue-o com POST /ddex. |
| 413 | too_large |
POST /ddex |
Acima de 20 GB (corpo bruto) ou 512 MB (multipart). Use um upload direto. |
| 429 | busy |
POST /ddex/validate |
Testes demais ao mesmo tempo. Tente de novo em instantes. |
| 409 | upload_incomplete |
POST /ddex/uploads/{id}/commit |
Partes ausentes ou com tamanho errado. Envie-as e confirme de novo. |
| 409 | already_committed |
Uploads diretos | Já confirmado antes. status_url aponta para a entrega. |
| 409 | commit_in_progress |
POST /ddex/uploads/{id}/commit |
Outra confirmação deste upload está em andamento. |
| 400 | invalid_url |
POST /webhooks, PATCH /webhooks/{id} |
Não é uma URL https pública na porta 443. |
| 409 | too_many |
POST /webhooks |
Você já tem 20 endpoints. |
| 409 | endpoint_disabled |
Teste e reenvio de webhook | O endpoint está desativado. Ative-o primeiro. |
Cada página da referência lista os erros de cada endpoint. Escopos e erros reúne os comuns a todos.
Erros de validação
Um 400 invalid indica o primeiro problema encontrado:
{
"error": "updated_since is an ISO date or time.",
"code": "invalid",
"field": "updated_since"
}
Apenas um campo é informado por vez. Corrija-o e envie de novo. Se você construir um formulário sobre a API, mostre error ao lado do campo indicado por field.
Com arquivos DDEX é diferente. Um lote DDEX com problemas não gera 400. O teste responde 200 com todas as verificações e um veredito, e uma entrega responde 202 e informa os problemas por lançamento. Veja Entrega DDEX.
O que tentar de novo
- Tente de novo em caso de
429e5xx, e de erros de rede como timeouts e conexões resetadas. - Não tente de novo os outros
4xx. A mesma requisição recebe a mesma resposta. Corrija antes a requisição, a chave ou os escopos dela.
Para 429, aguarde o número de segundos de Retry-After. Para 5xx, espere mais a cada tentativa (1 s, 2 s, 4 s…) e desista depois de algumas. Veja Limites de requisições.
Leituras podem ser repetidas com segurança. Pense antes de repetir uma escrita. Um POST /ddex repetido depois de uma resposta perdida pode colocar o lote na fila duas vezes. Confira antes em GET /ddex.
Um tratador de erros em 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;
}
Com curl, adicione -w '%{http_code}' para ver o status, ou -i para ver os headers:
curl -i "https://api.hillsmusic.com/v1/releases/999999" \
-H "Authorization: Bearer $HILLS_API_KEY"
# HTTP/2 404
# {"error":"…","code":"not_found"}