docs
Guias de Integração

Proteções no saque Pix por chave

Visão Geral

Antes de enviar um saque por chave, o provedor de liquidação consulta a chave no diretório do Pix (DICT). Esse provedor limita as consultas e pode bloquear temporariamente a conta que repete consultas a chaves inexistentes. Quando isso acontece, todos os saques da conta sofrem.

Para evitar isso, a plataforma responde na hora com o que já sabe e evita consultas repetidas que fariam o provedor bloquear a conta. Existem três comportamentos, que você percebe na resposta do POST /api/pix/cash-out:

SituaçãoResposta da APITransação criada?Webhook?
Chave que o provedor já informou não existir422 imediatoNãoNão
Provedor bloqueando consultas429 imediato com Retry-AfterNãoNão
Limite de ritmo do provedor201 normal, envio até 90 s mais lentoSimSim, como sempre

Repetir uma chave já negada não bloqueia a conta nem o cliente: só aquela chave fica com a resposta guardada (15 minutos, ou até 30 se o provedor negá-la de novo em até 2 horas) e a plataforma devolve a mesma negativa sem consultar o provedor. Todas as outras chaves seguem normais.

Este comportamento depende do liquidante da sua conta: está ativo em alguns liquidantes e, nos demais, o fluxo não muda. Em caso de dúvida sobre a sua conta, consulte seu gerente de integração.

Chave inexistente (422)

Quando acontece: a primeira tentativa para uma chave inexistente segue o fluxo normal da sua conta: com aceite assíncrono, a API responde 201 e, depois, você recebe o webhook de falha informando que a chave não foi encontrada; com aceite síncrono, o erro volta na própria resposta. Se o provedor já respondeu recentemente que a chave não existe, a recusa pode vir já na primeira tentativa da sua conta. Quando o provedor responde que a chave não existe, a plataforma guarda essa resposta por 15 minutos. Durante esse tempo, novos envios para essa chave recebem a mesma negativa direto da plataforma (422 PIX_KEY_NOT_FOUND, details.cached: true), sem consultar o provedor.

  • Se, depois de vencer, o provedor negar a mesma chave de novo dentro de 2 horas, o novo registro vale 30 minutos. Esse é o máximo; nunca passa disso.
  • Tentativas respondidas pela plataforma não contam e não prorrogam o prazo. Só uma nova negativa do próprio provedor conta.
  • Só aquela chave é afetada. A conta, o cliente e todas as outras chaves seguem normais. Não é bloqueio nem punição.
  • Por que existe: o provedor aplica uma regra do DICT que suspende por cerca de 30 minutos todos os saques por chave da conta quando a mesma chave inexistente é consultada repetidas vezes. Guardar a resposta protege a conta inteira.
  • Uma chave recém-cadastrada pode levar até esse prazo para ser aceita.
  • Sem transação, sem reserva de saldo e sem webhook.
  • O externalId da requisição recusada não fica consumido e pode ser reutilizado.
{
  "code": "PIX_KEY_NOT_FOUND",
  "message": "Chave Pix não encontrada",
  "details": {
    "retryAfterSeconds": 780,
    "source": "provider-guard",
    "cached": true
  }
}

retryAfterSeconds (e o cabeçalho Retry-After) trazem sempre o tempo real que falta.

O que fazer: trate como a falha de chave não encontrada que chegaria por webhook: peça ao usuário para conferir a chave. Se a chave foi cadastrada agora, aguarde retryAfterSeconds e tente de novo.

A negativa de chave inexistente pode chegar de duas formas. Trate as duas como a mesma situação (a chave não existe): corrija antes de reenviar.

Origem da negativaComo chegaIdentificação
ProvedorFalha do saque (webhook)errorCode e errorMessage do liquidante (o errorCode varia conforme o liquidante e não deve ser usado para lógica)
Registro da plataforma422 na respostacode PIX_KEY_NOT_FOUND, details.cached: true e details.retryAfterSeconds

Linha do tempo de exemplo:

10:00  Saque para a chave X
       -> 201, depois webhook de falha "chave não encontrada"
10:02  Novo saque para a chave X
       -> 422 imediato do registro, retryAfterSeconds ~ 780, cached: true
10:15  O registro vence
10:16  Novo saque para a chave X
       -> consulta o provedor de novo
       -> se negar de novo, novo registro de 30 minutos (até 10:46)

Saque já aceito: em contas com aceite assíncrono (resposta 201 e resultado por webhook), a chave pode ser registrada como inexistente depois de o saque ter sido aceito e antes de ele ser enviado ao provedor, por exemplo quando vários saques para a mesma chave são enviados ao mesmo tempo. Nesse caso o saque é encerrado com erro de chave inexistente e o valor reservado é liberado, exatamente como se o provedor tivesse negado. O aviso chega pelo webhook de falha normal. Em contas com aceite síncrono a mesma checagem acontece na própria chamada e o erro volta na resposta.

Saques sem details.document são validados pelo provedor de forma assíncrona: a recusa chega depois por webhook, em geral sem detalhar o motivo. Por isso a chave entra no registro principalmente a partir de envios com documento; depois de registrada, a resposta guardada vale para qualquer envio para aquela chave, com ou sem documento. Informe o documento do recebedor sempre que possível: o erro volta na hora e com o motivo.

Provedor bloqueando consultas (429)

Quando acontece: o provedor bloqueou temporariamente as consultas de chave. Enquanto ele estiver bloqueando, a maior parte dos saques por chave com documento do recebedor informado é recusada na hora, sem transação, sem reserva e sem webhook.

  • Dura só enquanto o provedor estiver bloqueando.
  • A cada 30 segundos, no máximo um saque é liberado para testar se o provedor voltou. Esse saque é aceito normalmente (201) e, se o bloqueio continuar, termina em erro pelo webhook, com o valor reservado devolvido. Quando o teste dá certo, a proteção é encerrada.
  • Esse bloqueio é do provedor (regra de consultas ao DICT), não uma punição da plataforma. A proteção existe justamente para evitar que ele aconteça.

A resposta traz o cabeçalho Retry-After e details.retryAfterSeconds (60).

HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{
  "code": "TOO_MANY_PIX_KEYS_NOT_FOUND",
  "message": "Muitas tentativas com chaves Pix inexistentes. Saque por chave bloqueado temporariamente; tente novamente em instantes.",
  "details": {
    "retryAfterSeconds": 60,
    "source": "provider-guard"
  }
}

O que fazer: aguarde o tempo de Retry-After e tente de novo, com backoff se a recusa persistir. Nada foi criado nem reservado.

10:00  Provedor bloqueia consultas de chave
10:00  Saque por chave com documento -> 429 imediato, Retry-After: 60
10:00:30  Um saque é liberado como teste -> 201, se o provedor ainda bloquear, webhook de falha
10:01  Nova tentativa -> 429 (ainda bloqueado)
10:03  Provedor libera; a plataforma detecta sozinha
10:03  Nova tentativa -> 201, fluxo normal

Limite de ritmo do provedor (envio mais lento)

Quando acontece: o volume de consultas se aproxima do limite do provedor.

O que a API responde: o saque é aceito normalmente (201) e pode levar até 90 segundos a mais para ser enviado ao provedor. O resultado chega pelo webhook como sempre. A espera só se aplica a saques com documento do recebedor informado, em contas com aceite assíncrono; saques sem documento não são atrasados.

O que fazer: nada. Não reenvie o saque por causa da demora: consulte o status antes (veja Monitoramento de Status).

10:00:00  Saque aceito -> 201 (PENDING)
10:01:20  Saque enviado ao provedor (atraso de até 90 s)
10:01:23  Webhook com o resultado

O que muda para quem integra

AntesAgora
Chave inexistente repetida201 e webhook de falha a cada tentativa422 imediato enquanto o registro da chave estiver ativo, sem transação e sem webhook
Provedor bloqueando consultas201 e webhook de falha minutos depois429 imediato, sem transação e sem webhook, para quase todos. A cada 30 s um saque é liberado como teste e pode falhar por webhook
Limite de ritmo201 e webhook201 e webhook, envio até 90 s mais lento

Você precisa tratar a recusa síncrona (422 e 429) na própria resposta da requisição. Para as recusas 422 e 429 nenhum webhook será enviado, então não fique esperando um. Um 201 recebido durante o bloqueio é um saque real (o teste do provedor) e segue o fluxo normal, inclusive o webhook.

Boas práticas

  • Trate PIX_KEY_NOT_FOUND com cached: true exatamente como a falha de chave não encontrada que chegaria por webhook: peça ao usuário para conferir a chave.
  • Ao receber PIX_KEY_NOT_FOUND, corrija a chave antes de reenviar. Não faça retry automático da mesma chave e respeite retryAfterSeconds.
  • Não repita em laço a mesma chave inválida: a resposta será a mesma até o prazo vencer.
  • Respeite Retry-After e details.retryAfterSeconds, com backoff se a recusa persistir.
  • Informe details.document do recebedor sempre que souber: os erros chegam na hora, e não minutos depois por webhook.
  • Não reenvie o mesmo saque sem conferir o status. A idempotência é por externalId; veja PIX Cash-Out.

Perguntas frequentes

Nesta página