Erros
O formato único, os códigos e o que fazer com cada um.
Todo erro da API tem a mesma forma. Um switch na sua ponta funciona para todas as rotas, e continua funcionando quando um código novo aparecer.
O formato
{
"error": {
"type": "invalid_request_error",
"code": "conversation_not_found",
"message": "The conversation could not be found.",
"param": "conversation_id",
"request_id": "req_01K7ZFA5X8Q2M4N6P8R0T2V4W6",
"doc_url": "https://developers.amivu.com.br/docs/resources/errors#conversation_not_found"
}
}
Nunca há stack trace, nome de tabela ou mensagem de banco. Um 500 devolve uma frase genérica e o request_id — o que o suporte precisa está no nosso log, não na sua tela.
type e code
type é a classe, e é ela que decide o que o seu código faz: repetir (rate_limit_error), corrigir a chamada (validation_error) ou avisar alguém (api_error). São sete, e a lista não cresce.
code é o caso concreto. A lista cresce sempre — e é justamente por isso que ela não faz parte do contrato de tipos: acrescentar um caso não pode quebrar quem consome.
switch exaustivo sobre code quebra no dia em que a API ganhar um caso novo. Decida pelo type, e guarde o code no seu log para investigar depois.Códigos HTTP
Uma avaliação assistida concede acesso temporário à organização, não uma assinatura paga. Ao vencer ou ser encerrada, as chamadas que exigem acesso ativo voltam a ser recusadas se não houver assinatura ou outra concessão válida. Solicite ao dono da conta que revise a contratação no painel; repetir a chamada não renova a avaliação. Envios pendentes também podem falhar após o término. Os dados não são apagados por esse motivo.
| 200 | OK | Deu certo. |
| 201 | Created | O recurso foi criado. |
| 400 | Bad Request | O corpo não é JSON válido. |
| 401 | Unauthorized | Credencial ausente, inválida, revogada ou expirada. |
| 403 | Forbidden | Credencial válida, alcance insuficiente. |
| 404 | Not Found | O recurso não existe nesta organização. |
| 409 | Conflict | O estado atual recusa a operação. |
| 413 | Payload Too Large | O corpo passou de 1 MB — ou, no upload, o arquivo passou de 16 MB. |
| 415 | Unsupported Media Type | O tipo do corpo ou do arquivo não é aceito. |
| 422 | Unprocessable Entity | O formato está certo, o conteúdo não passa na regra. |
| 429 | Too Many Requests | Excedeu o limite. Veja `Retry-After`. |
| 500 | Internal Server Error | Falha nossa. Cite o `request_id`. |
Catálogo de códigos
| Código | HTTP | Significado |
|---|---|---|
| missing_api_key | 401 | O cabeçalho Authorization não veio. |
| invalid_api_key | 401 | A chave não existe ou foi digitada errada. |
| revoked_api_key | 401 | A chave foi revogada no painel. |
| expired_api_key | 401 | A chave passou da data de expiração. |
| insufficient_scope | 403 | A chave não carrega o escopo exigido. |
| environment_mismatch | 403 | O recurso pertence ao outro ambiente. |
| subscription_required | 403 | A organização está sem assinatura ativa. |
| contact_not_found | 404 | Contato inexistente nesta organização. |
| conversation_not_found | 404 | Conversa inexistente nesta organização. |
| message_not_found | 404 | Mensagem inexistente nesta organização. |
| channel_not_found | 404 | Canal inexistente nesta organização. |
| tag_not_found | 404 | Etiqueta inexistente nesta organização. |
| team_not_found | 404 | Time inexistente nesta organização. |
| user_not_found | 404 | Atendente inexistente nesta organização. |
| webhook_not_found | 404 | Endpoint de webhook inexistente. |
| delivery_not_found | 404 | Entrega de webhook inexistente. |
| attachment_not_found | 404 | Anexo inexistente ou expirado. |
| resource_not_found | 404 | A rota existe, o recurso não. |
| unknown_endpoint | 404 | Não existe rota para este método e caminho. |
| invalid_id_format | 422 | O identificador não tem o prefixo esperado. |
| invalid_cursor | 422 | O cursor não corresponde a nenhum registro. |
| invalid_body | 400 | O corpo não é JSON válido. |
| unsupported_message_type | 422 | O canal desta conversa não suporta este tipo. |
| attachment_type_mismatch | 422 | O anexo não é do tipo pedido em `type` — um PDF não sai como `image`. |
| channel_not_connected | 422 | O canal existe mas não está conectado. |
| contact_without_address | 422 | O contato não tem endereço para este canal. |
| duplicate_contact | 409 | Já existe contato com este telefone, e-mail ou external_id. |
| idempotency_key_reuse | 409 | A mesma chave de idempotência com corpo diferente. |
| idempotency_in_progress | 409 | A requisição anterior com esta chave ainda está em curso. |
| rate_limit_exceeded | 429 | Excedeu o limite de requisições da organização. |
| payload_too_large | 413 | O corpo ou o arquivo passou do limite. |
| unsupported_media_type | 415 | O tipo MIME não é aceito — no upload, fora da lista de mídia que o envio aceita. |
| internal_error | 500 | Falha inesperada. O request_id identifica a ocorrência. |
O request id
Toda resposta — inclusive as de erro — traz X-Amivu-Request-Id, e o mesmo valor aparece no corpo do erro. Ele é o que transforma “deu erro ontem à tarde” numa linha exata.
Guarde-o no seu log. No painel, em Configurações → Desenvolvedores → Registro de chamadas, cole o valor para ver método, rota, status, duração e qual chave fez a chamada.
Veja também Limite de requisições.
Escrevemos sobre operação de atendimento, canais e IA no blog da Amivu.