Pular para o conteúdo

Erros

Todo erro da API sai no mesmo formato, em qualquer rota e em qualquer status.

{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "Chave de API inválida, revogada ou expirada.",
"request_id": "0a8c1f2e-3b4d-4c5f-9a6b-7c8d9e0f1a2b",
"doc_url": "https://docs.fatureihoje.com/errors#api_key_invalid"
}
}
CampoSempre vemO que é
typeSimA família do erro. Serve para você ramificar por faixa, sem conhecer cada código
codeSimO caso exato. É por ele que o seu programa decide o que fazer
messageSimFrase para pessoa ler. Sai no idioma de Accept-Language
doc_urlSimEndereço desta página, na âncora do código
request_idEm /public/v1Identificador desta chamada. É o que o suporte pede
paramNãoReservado. O contrato o prevê para o erro de um campo só, e nenhuma rota o emite hoje
errorsNãoLista de campos inválidos. Só no 422 de validação

O code é estável e escrito em inglês. Ele não muda de valor, não muda de nome e não muda com o idioma. Um código publicado no catálogo continua existindo mesmo quando a API para de emiti-lo, porque integração que o trata não pode quebrar.

A message é o contrário: é texto para uma pessoa ler e sai traduzida conforme o cabeçalho Accept-Language da requisição (pt-BR é o padrão, e en e es são aceitos).

Cada code tem um único status HTTP, e ele nunca varia. validation_failed é sempre 422; rate_limit_exceeded é sempre 429. É por isso que o catálogo abaixo publica os dois juntos: se você trata o código, o status é consequência, e nunca vai chegar um par diferente do que está aqui.

As sete famílias de type:

typeFaixaQuando
invalid_request_error400, 404, 413, 415A requisição está errada, ou o que ela pede não existe
authentication_error401A chave não foi aceita
permission_error403A chave foi aceita, mas esta ação não é permitida
conflict_error409Conflito com o estado atual
validation_error422Campo inválido
rate_limit_error429Orçamento de chamadas esgotado
api_error500, 503O problema é nosso

Quando um ou mais campos são inválidos, o corpo traz a lista, campo a campo:

{
"error": {
"type": "validation_error",
"code": "validation_failed",
"message": "Um ou mais campos são inválidos.",
"errors": [
{ "param": "email", "code": "invalid", "message": "E-mail inválido" },
{ "param": "phone", "code": "invalid", "message": "Telefone inválido" }
],
"request_id": "6f12b0d4-8e33-4a91-b2c7-5d0a7e93f118",
"doc_url": "https://docs.fatureihoje.com/errors#validation_failed"
}
}

param é o nome do campo como a API o recebe. message é texto para pessoa; o que o seu programa usa é param.

Esse param é o de dentro de errors, e é o único que você vai ver hoje. O param do nível de cima, ao lado de code, está previsto no contrato mas nenhuma rota o emite: leia sempre a lista errors.

Toda resposta de /public/v1, com erro ou sem erro, traz o cabeçalho Request-Id. No corpo de erro, o mesmo valor aparece em request_id.

Guarde esse valor no seu registro sempre que uma chamada falhar. É por ele que o suporte acha a chamada, e é o único caminho quando o erro é interno.

Caminho fora de /public/v1 responde 404 antes de a chamada ganhar um identificador, e por isso esse 404 sai sem request_id. Se você recebeu um erro sem request_id, confira primeiro o caminho.

O doc_url aponta para esta página, já na âncora do código:

https://docs.fatureihoje.com/errors#api_key_invalid

Em inglês e em espanhol o endereço leva o idioma: docs.fatureihoje.com/en/errors#... e docs.fatureihoje.com/es/errors#.... Pode registrar esse endereço no seu log de erro: ele é curto, permanente, e leva direto à explicação do código.

O exemplo chama GET /public/v1/me e trata as duas saídas: a resposta boa e o corpo de erro. Vale para qualquer rota, porque o formato do erro é o mesmo em todas.

Terminal window
curl -sS -i https://api.fatureihoje.com/public/v1/me \
-H "Authorization: Bearer $FH_API_KEY" \
-H "Accept-Language: pt-BR"

O -i imprime os cabeçalhos antes do corpo, então o Request-Id aparece junto do erro.

Esta é a lista inteira. Ela é gerada do contrato da API no build do site, então código novo aparece aqui sozinho e nenhum código fica de fora.

Código HTTP Tipo
api_key_invalid 401 authentication_error
access_denied 403 permission_error
permission_missing 403 permission_error
member_permission_denied 403 permission_error
member_suspended 403 permission_error
organization_suspended 403 permission_error
subscription_inactive 403 permission_error
plan_feature_unavailable 403 permission_error
plan_limit_reached 403 permission_error
resource_not_found 404 invalid_request_error
route_not_found 404 invalid_request_error
invalid_request 400 invalid_request_error
validation_failed 422 validation_error
conflict 409 conflict_error
idempotency_key_reused 422 validation_error
idempotency_in_progress 409 conflict_error
unsupported_media_type 415 invalid_request_error
request_too_large 413 invalid_request_error
rate_limit_exceeded 429 rate_limit_error
request_failed 400 invalid_request_error
internal_error 500 api_error
service_unavailable 503 api_error
api_key_invalid 401 authentication_error

Mensagem Chave de API inválida, revogada ou expirada.

O que fazer Confira o cabeçalho Authorization: Bearer <chave>, se a chave continua ativa no painel e se o IP de saída do seu servidor está na lista da chave. A resposta é a mesma em todos esses casos, de propósito: ela não diz qual foi o motivo.

access_denied 403 permission_error

Mensagem Você não tem acesso a este recurso.

O que fazer Acesso negado sem causa conhecida. Este código sai quando o motivo não é a permissão da chave nem a do membro. Guarde o request_id e fale com o suporte.

permission_missing 403 permission_error

Mensagem Esta chave não tem a permissão exigida por esta rota.

O que fazer Veja o que a chave tem em key.permissions, na resposta de GET /public/v1/me, e compare com o que a rota exige na Referência. A permissão de uma chave não muda depois de criada, nem na rotação: para mudar, crie outra chave.

member_permission_denied 403 permission_error

Mensagem O membro que esta chave representa não tem acesso a esta ação.

O que fazer A chave tem a permissão, mas o membro que ela representa não pode fazer isso no painel. Ajuste o papel ou as permissões desse membro, ou use uma chave de outro membro.

member_suspended 403 permission_error

Mensagem O membro que esta chave representa está suspenso.

O que fazer Reservado. Hoje o membro suspenso cai no 401 de api_key_invalid, porque a resposta da autenticação não pode dizer que a chave é válida. Se este código aparecer, reative o membro no painel.

organization_suspended 403 permission_error

Mensagem A empresa desta chave está suspensa.

O que fazer Reservado, pelo mesmo motivo do anterior, só que para a empresa. Se aparecer, resolva a situação da empresa no painel.

subscription_inactive 403 permission_error

Mensagem A assinatura da empresa não está ativa.

O que fazer Regularize o pagamento no painel. Repetir a chamada antes disso devolve o mesmo erro, então não vale a pena tentar de novo em laço.

plan_feature_unavailable 403 permission_error

Mensagem O plano da empresa não inclui este recurso da API.

O que fazer A API está disponível a partir do plano Start. O mesmo código sai quando a API foi desligada para essa empresa em particular.

plan_limit_reached 403 permission_error

Mensagem O limite do plano para este recurso foi atingido.

O que fazer O mais comum é o número de chaves ativas. Veja o uso no painel, revogue o que não usa mais ou suba de plano.

resource_not_found 404 invalid_request_error

Mensagem Recurso não encontrado.

O que fazer O id não existe ou é de outra empresa. A API responde 404 nos dois casos, nunca 403: dizer 403 contaria que o registro existe em outro lugar. Confira o id e a empresa da chave em GET /public/v1/me.

route_not_found 404 invalid_request_error

Mensagem Rota não encontrada.

O que fazer O caminho não existe. Confira o método, o caminho e o endereço: api.fatureihoje.com serve só /public/v1. Rota de área que ainda não foi publicada também responde assim.

invalid_request 400 invalid_request_error

Mensagem Requisição inválida.

O que fazer A requisição está malformada, quase sempre JSON quebrado ou parâmetro de consulta inválido. Corrija antes de repetir: repetir igual devolve o mesmo erro.

validation_failed 422 validation_error

Mensagem Um ou mais campos são inválidos.

O que fazer O corpo traz errors, com param, code e message de cada campo. Corrija o que ele aponta e reenvie: a mesma requisição devolve o mesmo erro.

conflict 409 conflict_error

Mensagem A operação conflita com o estado atual do recurso.

O que fazer Leia o recurso de novo e decida a partir do que ele diz agora. Repetir sem reler devolve o mesmo conflito. É o que responde, por exemplo, a mudança de situação de compromisso que a agenda não permite (cancelado não volta, concluído só volta para confirmado), a edição de ordem de serviço já concluída ou cancelada, a edição de orçamento aprovado ou cancelado, a exclusão de orçamento que já virou venda ativa a segunda conversão do mesmo orçamento em venda ou em OS, iniciar, concluir ou cancelar OS já concluída ou cancelada, qualquer escrita em orçamento absorvido numa junção, o código interno (sku) que já existe na empresa, o nome de variação repetido no mesmo produto, a exclusão de categoria que ainda tem produto ou serviço, e na venda: qualquer escrita em venda cancelada, versão nova ou cancelamento com nota fiscal ativa, versão nova com a comissão do vendedor já paga, receber ou reagendar venda de contrato, estornar recebimento já estornado ou com nota ativa, e reagendar sem parcela em aberto. No financeiro: mudar campo protegido de lançamento de venda ou do banco, excluir lançamento de venda ou do banco, marcar como pago lançamento cancelado ou na fatura, excluir conta que tem lançamento, e a exclusão de série que apagaria mais do que o pedido (com param scope).

idempotency_key_reused 422 validation_error

Mensagem Esta Idempotency-Key já foi usada com um corpo diferente.

O que fazer Gere um valor novo para cada operação diferente. Repetir a chave só vale para repetir a MESMA requisição, byte a byte.

idempotency_in_progress 409 conflict_error

Mensagem Uma requisição com esta Idempotency-Key ainda está em andamento.

O que fazer Espere alguns segundos e repita a mesma requisição, com a mesma chave. Não gere chave nova: isso executaria a operação duas vezes.

unsupported_media_type 415 invalid_request_error

Mensagem Envie o corpo em JSON, com Content-Type: application/json.

O que fazer Formulário, multipart e texto puro não são aceitos. Confira o Content-Type que a sua biblioteca manda por padrão.

request_too_large 413 invalid_request_error

Mensagem O corpo da requisição passou do limite de 1 MB.

O que fazer Quebre o envio em partes menores. O teto vale para toda chamada, com ou sem Idempotency-Key.

rate_limit_exceeded 429 rate_limit_error

Mensagem Limite de chamadas por minuto atingido. Tente de novo em instantes.

O que fazer Espere o que o cabeçalho Retry-After diz e recue progressivamente. Não repita em laço apertado: o orçamento é da empresa e você atrasa as chamadas boas dela.

request_failed 400 invalid_request_error

Mensagem Não foi possível processar a requisição.

O que fazer A API não processou a requisição e o motivo não tem código próprio no catálogo. Guarde o request_id. Se o erro se repetir com a mesma requisição, mande o request_id para o suporte.

internal_error 500 api_error

Mensagem Erro interno. Se persistir, informe o request_id ao suporte.

O que fazer O problema é do nosso lado, e a resposta nunca traz detalhe interno, de propósito. Pode tentar de novo depois de esperar. Se persistir, mande o request_id para dev@fatureihoje.com.

service_unavailable 503 api_error

Mensagem API indisponível no momento. Tente de novo em instantes.

O que fazer A causa é configuração de borda, não a sua requisição. Espere e tente de novo. Se durar, avise o suporte com o request_id.

  • Limites de uso: o 429 e os cabeçalhos que dizem quanto sobrou.
  • Idempotência: os dois erros que aparecem quando você repete uma requisição.
  • Autenticação: o roteiro do 401, que é o erro mais comum no começo.