Erros
Todo erro da Liqfy é um objeto JSON com formato estável — programe seu handler contra ele uma vez e pare de adivinhar. Toda resposta, de sucesso ou de erro, também traz o cabeçalho X-Request-Id (gerado quando você não manda um, devolvido igual quando você manda).
#Formato
{
"error": {
"type": "invalid_request_error",
"code": "invalid_amount",
"message": "amount deve ser um inteiro positivo em centavos.",
"param": "amount",
"details": []
},
"request_id": "req_01J..."
}| Campo | Sempre presente | Descrição |
|---|---|---|
error.type | sim | Categoria estável — uma de invalid_request_error, authentication_error, permission_error, not_found_error, conflict_error, rate_limit_error, api_error. |
error.code | sim | Código de máquina estável, em snake_case. É nele que seu handler deve ramificar, não na message. |
error.message | sim | Explicação para humano. Pode logar; não é contrato para automação. |
error.param | quando é de um campo | Identifica o campo que falhou, quando não há ambiguidade. |
error.details | em falha de validação | Lista { param, message }[] para erro em vários campos. |
request_id | sim | Cite ao falar com o suporte — ele rastreia todo log, span e mensagem Kafka. Também vem no cabeçalho X-Request-Id. |
Por que
codee nãomessage: a mensagem é escrita para gente ler e muda sem aviso — inclusive de idioma. Ocodeé contrato. Umif (e.message === "Invalid API key")quebra na primeira vez que alguém melhorar a frase.
#Mapa de status
| HTTP | error.type | O que o cliente deve fazer |
|---|---|---|
| 200 | — | — |
| 201 | — | Guarde o id devolvido e siga. |
| 400 | invalid_request_error | Corrija o corpo/cabeçalhos e tente de novo. Não repita às cegas. |
| 401 | authentication_error | Confira se o cabeçalho apikey leva uma chave correta e ativa. |
| 403 | permission_error | Bloqueado por escopo ou pela guarda antifraude/velocidade. Revise o cliente ou fale com o suporte. |
| 404 | not_found_error | Confira o id que você mandou. |
| 409 | conflict_error | Mesma Idempotency-Key usada com corpo diferente — use uma chave nova. |
| 422 | invalid_request_error | Violação de regra de negócio — leia a message, corrija a entrada, não repita. |
| 429 | rate_limit_error | Reduza o ritmo. Repita com atraso exponencial + jitter; respeite o Retry-After quando vier. |
| 5xx | api_error | Seguro repetir com a mesma Idempotency-Key — a idempotência é o que te protege de duplicar. |
#Erros comuns
#400 Bad Request
Validação falhou — o error.code é invalid_request, a menos que exista um código mais específico (ex.: invalid_amount); o error.details lista cada campo que falhou.
{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "Validation failed",
"details": [
{ "param": "amount", "message": "must be a positive integer" },
{ "param": "payment_method", "message": "Invalid enum value" }
]
},
"request_id": "req_01J..."
}Também dá 400 quando falta o cabeçalho Idempotency-Key numa escrita financeira (POST /v1/charges, POST /v1/pix/charges).
Ação Corrija a requisição e tente de novo. Nunca em laço.
#401 Unauthorized
{
"error": {
"type": "authentication_error",
"code": "unauthorized",
"message": "Invalid API key"
},
"request_id": "req_01J..."
}Causas possíveis:
- Cabeçalho ausente — confira se o
apikey: lq_live_...está sendo enviado. - A chave foi girada — veja no painel.
- Espaço em branco — a chave é comparada exatamente, sem espaço na frente ou atrás.
Ação Verifique a chave. Se ela estiver certa, pode ter sido desativada — fale com o suporte.
#403 Forbidden
A guarda de fraude/velocidade barra a cobrança antes de ela chegar no provedor — o error.code sempre começa com fraud.:
{
"error": {
"type": "permission_error",
"code": "fraud.customer_velocity_exceeded",
"message": "Too many payment attempts for this customer in a short window"
},
"request_id": "req_01J..."
}Existe um segundo código fraud.* para o limite de velocidade da própria conta.
Ação Revise o cliente ou reduza o ritmo das tentativas. Se o bloqueio parecer errado, escreva para support@liqfy.com.br com o request_id.
#404 Not Found
{
"error": {
"type": "not_found_error",
"code": "not_found",
"message": "Charge ch_a1b2c3d4-0000-0000-0000-000000000009 not found"
},
"request_id": "req_01J..."
}Ação Confira o id. Se você acabou de criar o recurso, espere 1 a 2 segundos e tente de novo.
#409 Conflict
{
"error": {
"type": "conflict_error",
"code": "idempotency_key_reused",
"message": "Idempotency key 'ORD-7821' already used with a different request body"
},
"request_id": "req_01J..."
}Você reenviou uma Idempotency-Key com corpo diferente do original. A Liqfy recusa sobrescrever em silêncio.
Ação Use uma Idempotency-Key nova. Causa comum: reaproveitar o id do pedido depois que o cliente mexeu no carrinho.
#Recusa por regra de negócio
Falha de formato (campo faltando ou inválido) é 400 com error.type: "invalid_request_error". Algumas falhas de configuração mais abaixo — por exemplo, nenhum PSP configurado para o payment_method pedido — vêm repassadas do orquestrador interno com o status dele, normalmente 422 Unprocessable Entity:
{
"error": {
"type": "invalid_request_error",
"code": "unprocessable_entity",
"message": "no provider for PIX"
},
"request_id": "req_01J..."
}Ação Leia a message. Não repita — corrija a entrada, ou fale com o suporte se a conta deveria ter provedor configurado.
#429 Too Many Requests
{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Rate limit exceeded"
},
"request_id": "req_01J..."
}Cabeçalhos nessa resposta (veja os limites atuais em Primeiros passos):
Retry-After: 12
X-RateLimit-Limit-Minute: 5000
X-RateLimit-Remaining-Minute: 0Ação Reduza o ritmo — respeite o Retry-After quando vier, senão backoff exponencial com jitter.
async function comRetry(fn, tentativas = 5) {
for (let i = 0; i < tentativas; i++) {
try { return await fn(); }
catch (err) {
if (err.status !== 429 && err.status < 500) throw err;
const base = Math.min(1000 * 2 ** i, 30_000);
const jitter = Math.random() * 0.3 * base;
await new Promise(r => setTimeout(r, base + jitter));
}
}
throw new Error('tentativas esgotadas');
}#5xx — do lado do servidor
{
"error": {
"type": "api_error",
"code": "service_unavailable",
"message": "Upstream unavailable"
},
"request_id": "req_01J..."
}Seguro repetir. Use a mesma Idempotency-Key, para que uma cobrança duplicada nunca seja criada caso o processamento tenha dado certo e só a resposta tenha se perdido.
#Erros de entrega de webhook (servidor → seu endpoint)
Quando a Liqfy não consegue alcançar o seu endpoint, a falha aparece em GET /v1/webhooks/deliveries:
{
"id": "wd_...",
"status": "FAILED",
"attempts": 3,
"maxAttempts": 15,
"lastStatusCode": 502,
"lastError": "HTTP 502",
"lastResponseBody": "Bad Gateway",
"nextRetryAt": "2026-07-23T16:08:00.000Z"
}lastStatusCode / lastError | O que significa |
|---|---|
2xx | Entregue. Não retenta. |
4xx | Seu endpoint recusou o payload. A Liqfy ainda retenta até maxAttempts — corrija e reenvie se precisar. |
5xx | Seu endpoint está fora. A Liqfy retenta com backoff exponencial. |
429 / Retry-After | A Liqfy respeita o seu Retry-After e reagenda. |
Connection timeout / ETIMEDOUT | Seu endpoint levou mais de 30s. Responda 200 OK rápido e processe em fila. |
getaddrinfo ENOTFOUND | Seu domínio não resolve. Atualize a URL registrada. |
self signed certificate | Erro de TLS. A Liqfy exige certificado público válido. |
Depois de maxAttempts (padrão 15), a entrega vai para a DLQ e pode ser reenviada manualmente. Veja Webhooks para a semântica completa.
#Lendo o error.details
O error.details é uma lista plana de { param, message } — renderizável direto:
{error.details.map(({ param, message }) => (
<li key={param}>{param}: {message}</li>
))}#Quando escrever para o suporte
Fale com integrations@liqfy.com.br se:
- Um 5xx persistir por mais de 5 minutos
- Uma entrega de webhook ficar presa em
FAILEDdepois domaxAttempts - Um
403 Forbiddenaparecer sem explicação - A mesma
Idempotency-Keydevolver cobranças diferentes em chamadas diferentes (isso é bug — não pode acontecer)
Sempre cite o request_id — ele nos deixa rastrear todo log, span e mensagem Kafka numa consulta só.