Erros
A Merx API utiliza códigos HTTP padrão para indicar sucesso ou falha. Códigos 2xx indicam sucesso, 4xx indicam erros de cliente, 5xx indicam erros de servidor.
Formato de Erros
A API não tem um único formato de erro: existem quatro. Antes de escrever o tratamento de erros do seu cliente, confira qual deles se aplica — assumir sempre a chave messages quebra nos outros três.
(a) Objeto com array de mensagens — o mais comum
Validação de corpo, regra de negócio, recurso não encontrado. É o formato da maioria dos 400, 404, 409 e 502 e do 403 de módulo não contratado:
{
"messages": ["message.name.mandatory"]
}
O conteúdo do array é a chave de mensagem, não uma frase pronta para exibir ao usuário final: a API devolve message.name.mandatory, e não "o nome é obrigatório". Trate essas chaves como códigos estáveis — é nelas que você deve programar, e é você quem escolhe o texto mostrado ao seu usuário. A exceção é o 500 genérico, onde o array pode trazer a mensagem técnica da exceção em vez de uma chave.
O array pode trazer mais de uma mensagem quando vários campos do corpo são reprovados de uma vez.
(b) Objeto de quatro chaves — parâmetro com tipo errado
Quando um parâmetro de caminho ou query não converte para o tipo esperado (um id que deveria ser UUID, um número, um booleano), o corpo não usa a chave messages:
{
"timestamp": "2024-01-15T10:30:00.123",
"status": 400,
"error": "Bad Request",
"message": "message.creditscoreid.invalid"
}
A chave em message é derivada do nome do parâmetro (message.{parametro}.invalid), com o nome convertido para minúsculas.
(c) Mensagem em texto — 405 e 403 por enumeração desconhecida
Alguns erros devolvem apenas a mensagem, sem objeto JSON em volta:
"Request method 'PATCH' not supported"
Acontece no 405 (método não suportado) e no 403 por valor de enumeração desconhecido. Nesses casos a API devolve a mensagem da exceção diretamente, sem envelope: um parser que espera objeto falha. O 403 de módulo não contratado não entra aqui: ele vem no formato (a). O tipo do corpo depende da negociação de conteúdo — pode chegar como texto puro ou como string JSON entre aspas — então trate pelo código HTTP, não pelo corpo.
(d) Corpo cru do serviço downstream
Endpoints que apenas repassam a chamada para outro serviço da Merx (financeiro, carbono, baseline, order) devolvem, em caso de erro lá, o status HTTP original do serviço de origem. Se o corpo daquele serviço já for um objeto ou lista JSON, ele é repassado sem reescrita; caso contrário, é reembrulhado no formato (a). O formato final é o que aquele serviço produzir, e não necessariamente algum dos anteriores.
Códigos de Erro Comuns
400 — Bad Request
Validação de campo falhou:
{
"messages": ["message.producer.social-identity.invalid"]
}
Duas chaves frequentes que não aparecem por endpoint, porque valem para qualquer rota:
| Chave | Quando ocorre |
|---|---|
message.malformed-request | Corpo JSON sintaticamente inválido ou com tipo incompatível num campo. É o erro mais comum em POST e PUT |
message.duplicate.key | Violação de restrição de unicidade no serviço de destino |
401 — Unauthorized
Retornado pelo Kong gateway quando a Authorization está ausente ou inválida. A resposta traz body, no formato {"data": [], "error": {...}}. A mensagem dentro de error varia conforme o plugin de autenticação da rota, então trate pelo código HTTP e não pelo texto.
Existe também um 401 repassado de serviço downstream, esse sim sem body: nesse caso o gateway aceitou a chave, mas o serviço interno acionado recusou a credencial. O corpo é justamente o que distingue os dois — o do gateway traz
{"data": [], "error": {...}}e o de downstream vem vazio. Ainda assim, trate pelo código HTTP.
403 — Forbidden
Na API de integração o formato do corpo do 403 depende da origem.
Módulo não contratado — a cooperativa chamou uma rota de um módulo que não contratou. Corpo em formato (a):
{
"messages": ["message.module.not-contracted"]
}
Valor de enumeração desconhecido — a API recebeu um valor de enumeração que não sabe mapear: tipo de pessoa, estado civil, tipo de signatário ou papel de assinatura. Corpo em formato (c): a mensagem da exceção, sem envelope JSON. O corpo é o texto Unexpected value: <valor>, em inglês e sem chave de mensagem, então não programe em cima dele.
O 403 do gateway, por chave de API sem permissão, está descrito em Autenticação.
405 — Method Not Allowed
Corpo em formato (c): a descrição do método recusado, sem envelope JSON.
"Request method 'PATCH' not supported"
Ocorre quando o verbo HTTP não é suportado pela rota — por exemplo, um PATCH em uma rota que só aceita PUT.
409 — Conflict
{
"messages": ["descrição do conflito"]
}
Conflito de estado: a operação é válida, mas colide com um registro já existente.
415 — Unsupported Media Type
Sem body de resposta. Ocorre quando o header Content-Type está ausente ou não é application/json.
Atinge inclusive requisições sem corpo: os endpoints
DELETE /api/v1/integration/webhooks/{id}eDELETE /api/v1/integration/owner-details/{id}exigemContent-Type: application/jsone respondem 415 sem ele.
404 — Not Found
{
"messages": ["message.entidade.not-found"]
}
Nota: Nem todo endpoint sem resultado responde da mesma forma. Consultas por identificador retornam 404 em vez de corpo vazio — por exemplo,
GET /api/v1/integration/producers/-/documents/{social_identity}retorna{"messages": ["message.producer.not-found"]}quando o documento não corresponde a nenhum produtor. Já os endpoints de listagem (comoGET /api/v1/integration/webhooks) retornam 200 com um array vazio.
500 — Internal Server Error
{
"messages": ["mensagem interna do erro"]
}
Falha não tratada no processamento. A chave messages traz a mensagem interna da exceção — ou message.internal.error quando não há mensagem. Casos conhecidos: valor acima do tamanho da coluna no banco (uma url de webhook com mais de 250 caracteres, um hmac_secret com mais de 120) e o DELETE /api/v1/integration/owner-details/{id}, que falha em toda chamada.
502 — Bad Gateway
{
"messages": ["message.integration.connection.refused"]
}
Ocorre quando um serviço downstream está indisponível ou recusa a conexão — a chamada nem chega a ser respondida pelo serviço de destino.
Status espelhado do serviço downstream
Quando o serviço interno responde, mas com erro, a API repassa o status HTTP dele (400, 404, 422, 500 — o que vier) junto com o corpo cru da resposta, no formato (d). Isso significa que:
- o status recebido pode não constar desta lista;
- o corpo pode não ter a chave
messages; - a mesma rota pode devolver o formato (a) para erros de validação da integração e o formato (d) para erros do serviço de origem.
Trate o corpo de erro de forma defensiva: verifique se é um objeto e se a chave messages existe antes de acessá-la.
Exemplos por Domínio
| Domínio | Erro Comum | Mensagem |
|---|---|---|
| Cadastros | Produtor não encontrado | message.producer.not-found |
| Cadastros | CPF/CNPJ duplicado | message.producer.already-exists |
| Comercial | Carteira não encontrada | message.wallet.not-found |
| Acesso | Módulo não contratado | message.module.not-contracted |
| Autenticação | Header ausente ou inválido | Authorization ausente ou inválido (401 do gateway, com body {"data": [], "error": {...}}) |