Políticas e Regras
As políticas permitem configurar regras preventivas para operações PIX. Elas são configuradas no painel (Backoffice) e avaliadas automaticamente pela API. Tudo que a tela oferece é avaliado em runtime: PIX Out, PIX In, QR Code, chaves, estorno, horário de operação e limites de DICT.
Hierarquia de Configuração
As políticas têm dois níveis:
Tenant (base) -> Account (sobrescreve o tenant)
A resolução é por seção: se a conta define pixOut, a seção pixOut da conta é usada inteira, e a do tenant é ignorada. Seções não definidas na conta são herdadas do tenant. Uma seção que não existe em nenhum dos dois níveis simplesmente não é avaliada — não há um nível "default" por trás com valores implícitos.
A única exceção são os limites de DICT, que têm defaults globais da plataforma quando a policy não os define — ver Limites de DICT Lookup.
Regras de PIX Out
As regras são avaliadas nesta ordem:
| Ordem | Regra | rule | Descrição |
|---|---|---|---|
| 1 | Kill Switch | pixOutDisabled | enabled: false recusa toda saída. É absoluto — vence inclusive a whitelist |
| 2 | Whitelist | — | Documento do destinatário na whitelist: permite e pula todas as regras abaixo |
| 3 | Blacklist | cpfCnpjBlacklist | Recusa se o documento do destinatário está na blacklist |
| 4 | Mesma Titularidade | sameOwnershipOnly | Permite apenas transferências para o CPF/CNPJ do titular da conta |
| 5 | Horário de Operação | operatingHours | Recusa fora da janela configurada |
| 6 | Limite por Transação | maxAmount | Valor máximo por transferência |
| 7 | Limite Noturno | nightMaxAmount | Valor máximo entre 20:00 e 06:00 (BRT) |
| 8 | Tipo de Pessoa | allowedPersonTypes | Restringe o destinatário a PF ou PJ (pelo tamanho do documento) |
Ao contrário da whitelist, que curto-circuita, as demais regras são todas avaliadas: uma transação pode violar mais de uma, e o violations da resposta traz todas.
Duas fases de avaliação
O documento do destinatário nem sempre existe no momento do POST:
- No POST (borda): kill switch, horário e limites de valor. As regras de documento também, quando o modo é
BANK_ACCOUNT, o único que trazdocumentNumberno corpo. - Depois de resolver o destinatário: nos modos
KEYeQRCODE, o documento só aparece quando a chave é consultada no DICT ou o BR Code é decodificado. As regras de documento são avaliadas nesse ponto, antes de o pagamento ser submetido ao parceiro. O mesmo vale para os limites de valor quando um QR Code é pago semamountno corpo: o montante vem do BR Code, e o limite é aplicado assim que ele é conhecido.
Na prática isso significa que uma violação de blacklist no modo chave não devolve 422 na resposta do POST: o pagamento é aceito, o paymentId é criado, e o desfecho é FAILED com errorCode: policy_denied. O webhook policy.violation e o pix.out.failed avisam do resultado.
Resposta a uma violação (fase de POST)
HTTP/1.1 422 Unprocessable Entity
{
"errorCode": "policy_denied",
"message": "amount R$ 5000.00 exceeds the per-transaction limit of R$ 1000.00",
"violations": [
{ "rule": "maxAmount", "message": "amount R$ 5000.00 exceeds the per-transaction limit of R$ 1000.00" }
]
}
Não é 403 (que significa falta de permissão) nem 400 (o payload é válido): a requisição está correta e foi recusada por uma regra que o próprio tenant configurou.
Modo monitor (NOTIFY_ONLY)
O campo violationAction da seção pixOut define o que fazer com as violações:
| Valor | Efeito |
|---|---|
BLOCK (padrão) | Recusa o pagamento |
NOTIFY_ONLY | Registra a violação e envia o webhook policy.violation, mas o pagamento segue |
NOTIFY_ONLY é o ensaio antes do bloqueio: salve a regra em modo monitor, acompanhe os avisos por alguns dias no painel e no webhook, e promova para BLOCK quando estiver convencido de que a regra não pega tráfego legítimo.
Em modo monitor a violação não aparece na timeline da transação — o pagamento seguiu e vai ter o desfecho normal (pix_out.completed). A violação vive no webhook e no painel.
Regras de PIX In
O liquidante credita a conta e só depois nos avisa. Quando a política é avaliada, o dinheiro já entrou — não existe momento em que dava para recusar. Por isso a seção não tem kill switch, e a escolha é sobre o que fazer depois: avisar, ou devolver.
| Ordem | Regra | rule | Descrição |
|---|---|---|---|
| 1 | Whitelist | — | Documento do pagador na whitelist: aceita e pula todas as regras abaixo |
| 2 | Blacklist (documento) | pixIn.cpfCnpjBlacklist | Pagador com documento na blacklist |
| 3 | Mesma Titularidade | pixIn.sameOwnershipOnly | Aceita apenas PIX do CPF/CNPJ do titular da conta |
| 4 | Limite por Transação | pixIn.maxAmount | Valor máximo recebido por transação |
| 5 | Tipo de Pessoa | pixIn.allowedPersonTypes | Restringe o pagador a PF ou PJ |
| 6 | Bancos Permitidos | pixIn.allowedBankCodes | Aceita apenas PIX dos bancos listados |
| 7 | Bancos Bloqueados | pixIn.blacklistedBankCodes | Recusa PIX dos bancos listados |
As listas de banco aceitam código COMPE (3 dígitos) ou ISPB (8 dígitos) — o que você tiver em mãos. Quando o webhook do liquidante não identifica o banco do pagador, as regras de banco são puladas em vez de acusar violação. Vale o mesmo para as regras de documento quando o pagador vem sem CPF/CNPJ.
Ações de PIX In
violationAction | Efeito |
|---|---|
ALLOW_AND_NOTIFY (padrão) | Registra a violação e envia policy.violation. O crédito permanece |
AUTO_REFUND | Além de avisar, devolve o valor integral ao pagador |
AUTO_REFUND inicia uma devolução PIX comum logo após o crédito, com motivo unauthorized-transaction. Ela aparece no extrato do seu cliente como uma devolução e não tem como ser desfeita — comece com ALLOW_AND_NOTIFY para ver quais regras pegariam antes de devolver dinheiro de verdade.
O webhook pix.in.completed é entregue nos dois casos, e antes do policy.violation: o crédito aconteceu, e esconder isso criaria divergência entre o seu saldo e o nosso. Quando há devolução, ela gera os eventos normais de PIX out (pix.out.completed ou pix.out.failed).
Regras de QR Code
Avaliadas na criação do QR Code (estático e dinâmico), antes de o QR existir no parceiro.
| Regra | rule | Descrição |
|---|---|---|
| Criação de estático | qrCode.canCreateStatic | false recusa a criação de QR estático |
| Criação de dinâmico | qrCode.canCreateDynamic | false recusa a criação de QR dinâmico |
| Valor mínimo | qrCode.minAmount | Valor mínimo do QR |
| Valor máximo | qrCode.maxAmount | Valor máximo do QR |
Os limites de valor só se aplicam a QR criado com valor. Um QR estático aberto, em que o pagador digita o valor no app do banco dele, não tem montante para comparar na criação — as duas regras de valor são puladas.
Regras de Chaves PIX
Avaliadas na criação de chave (POST /v1/accounts/{accountId}/pix/keys).
| Regra | rule | Descrição |
|---|---|---|
| Criação | keys.canCreate | false recusa a criação de novas chaves |
| Máximo de chaves | keys.maxKeys | Recusa quando a conta já tem esse número de chaves |
A contagem de chaves é consultada no parceiro no momento da criação. Se essa consulta falhar, a criação segue: indisponibilidade nossa não deve virar violação de política. Chaves que já existem nunca são removidas por uma mudança de política.
Regras de Estorno
Avaliadas nas devoluções que você pede em POST /v1/accounts/{accountId}/pix/out/refund, sejam elas integrais ou parciais.
| Regra | rule | Descrição |
|---|---|---|
| Kill switch | refund.disabled | enabled: false recusa toda devolução pedida pela API |
| Valor máximo | refund.maxAmount | Valor máximo por devolução |
Devoluções que não são sua escolha ficam fora desta seção: um MED aceito e o AUTO_REFUND da seção PIX In são obrigações, e regra de tenant não sobrepõe obrigação. Pelo mesmo motivo, as regras de documento de PIX Out (blacklist, whitelist, titularidade, tipo de pessoa) não se aplicam a devoluções — o destinatário de uma devolução é quem pagou, não uma escolha sua.
Recusa nas três seções acima
QR Code, chaves e estorno sempre barram: não há modo monitor. As três são operações síncronas que ainda não moveram dinheiro quando a regra é avaliada, então a recusa cabe na resposta — 422 com errorCode: policy_denied, no mesmo formato do PIX Out. Avisar depois de devolver um BR Code, publicar uma chave no DICT ou submeter uma devolução seria avisar sobre fato consumado.
Horário de Operação
Janela em que as saídas são permitidas. Suporta janelas que cruzam a meia-noite (ex.: 22:00-06:00).
| Campo | Descrição | Exemplo |
|---|---|---|
start | Hora de início | 06:00 |
end | Hora de fim | 22:00 |
timezone | Fuso horário (padrão America/Sao_Paulo) | America/Sao_Paulo |
Uma janela pela metade (só start ou só end) é tratada como ausente e não barra ninguém.
Limites de DICT Lookup
Consultar uma chave PIX tem limites próprios, avaliados a cada consulta. Ao exceder, a resposta é 429 com errorCode: dict_lookup_limit_exceeded, e um webhook policy.violation com phase: "dict_lookup" é enviado.
429 é a sua cotaA mesma rota também responde 429 com errorCode: partner_rate_limited, que é throttling do liquidante sobre o tráfego da CorpX e não tem relação com os limites desta página — nenhum contador da sua conta fechou. Confira o errorCode antes de concluir que a cota acabou.
Contam como consulta as duas formas de perguntar ao DICT quem é o dono de uma chave:
- A consulta explícita —
GET /v1/accounts/{accountId}/pix/key/{pixKey}. - O PIX Out no modo
KEY(em implantação) —POST /v1/accounts/{accountId}/pix/out,/asynce/bigpix. A chave precisa ser resolvida antes de o dinheiro sair, e essa pergunta vai para o mesmo DICT. Ver "Pagamento por chave também consome cota", abaixo.
São três limites de contagem absoluta, todos medidos por conta (ver "Todo limite é por conta", abaixo), e vale o mais restritivo — qualquer um que estoure devolve 429:
| Limite | Janela | Default global | O que protege |
|---|---|---|---|
maxLookupsPerDay | dia-calendário BRT (a partir de 00:00) | 50 | Teto absoluto de consultas por dia |
maxLookupsPerMinute | 60s rolantes | 15 | Rajada: cabe no teto diário, mas chega tudo de uma vez |
maxNotFoundPer5min | 5 min rolantes | 10 | Enumeração de chaves: scan cego gera muito NOT_FOUND antes de o teto diário estourar |
Além deles existem os tetos de taxa por janela de tempo, descritos a seguir. Esses valem sempre: quem não declara números próprios herda a linha de base da frota.
maxLookupRatio foi descontinuadoHavia um quarto limite, maxLookupRatio — consultas permitidas por transferência concluída nas últimas 24h. Ele saiu na v2.53.0. Era o mesmo cálculo da taxa de uso da janela de 24h, com resolução pior: uma janela só, sem piso de amostra próprio, dependendo de um piso global de 50 consultas para não travar conta sem transferência. As janelas fazem o mesmo em doze faixas. O campo continua sendo aceito no corpo da policy e é ignorado; o motivo de negação ratio não aparece mais nas respostas 429.
Tetos de taxa por janela de tempo
Os três limites acima respondem quanto e quão rápido. Nenhum responde a pergunta que o balde do DICT de fato mede: quantas consultas você gasta por pagamento que efetiva, e que fração das suas consultas não resolve chave nenhuma. Uma conta pode caber folgado em 500 consultas por dia e ainda assim gastar 40 consultas por PIX — perfil de quem varre chave, não de quem paga.
Cada janela de tempo pode ter teto para as duas taxas:
| Campo | O que mede |
|---|---|
maxUsageRatio | Consultas ÷ PIX Out concluídos na janela |
maxFailureRatio | (NOT_FOUND + recusadas) ÷ consultas na janela. É fração, não percentual: 0.4 = 40% |
minLookups | Piso de amostra. Abaixo desse número de consultas na janela, nenhuma das duas regras pode recusar |
As janelas disponíveis são 5m, 15m, 30m, 1h, 3h, 6h, 12h, 24h, 3d, 7d, 14d e 30d.
{
"dictLookup": {
"windows": {
"5m": { "maxFailureRatio": 0.6, "minLookups": 10 },
"1h": { "maxUsageRatio": 6, "maxFailureRatio": 0.4, "minLookups": 50 },
"30d": { "maxUsageRatio": 4, "minLookups": 500 }
}
}
}
O minLookups existe para o rate não travar quem mal começou: uma conta com duas consultas e nenhum pagamento tem taxa de uso infinita, e sem o piso ficaria bloqueada para sempre.
Janela sem teto declarado não é janela desligada. Ela herda a linha de base da frota, que hoje é maxUsageRatio 2.2 e maxFailureRatio 0.3 em todas as faixas, com piso de amostra de 20 nas janelas de até 30 minutos, 50 de 1h a 12h e 500 por dia de janela a partir de 24h (500 em 24h, 1500 em 3d, e assim por diante). Esses números saíram da medição de 14 dias de tráfego real e não barravam nenhuma conta no histórico. Declarar valores próprios na policy especializa a conta ou o tenant; não é o que liga a proteção.
Quando mais de uma janela está acima do teto, a resposta cita a mais curta — é a causa imediata e a primeira a liberar. A mensagem do 429 diz qual janela, o que foi medido e qual era o teto:
DICT lookup usage too high for this account in the last 1h:
120 lookups for 10 successful transfers (12.0 per transfer); max 6.0
DICT lookup failure rate too high for this account in the last 5m:
18 of 24 lookups did not resolve a key (75%); max 40%
O errorCode continua sendo dict_lookup_limit_exceeded — nada muda para quem já trata esse código.
Todo limite é por conta
Todos os limites são medidos conta a conta, sempre. Não existe teto agregado por tenant: as consultas de uma conta nunca entram na contagem de outra, mesmo que as duas pertençam ao mesmo tenant.
Isso vale inclusive quando o limite foi configurado no nível do tenant. Uma policy de tenant é um molde aplicado a cada conta individualmente, não um balde compartilhado:
| Configuração | Leitura correta | Leitura errada |
|---|---|---|
Policy do tenant com maxLookupsPerDay: 50 | Cada conta do tenant pode fazer 50 consultas por dia | |
Policy do tenant com windows.24h.maxUsageRatio: 2.2 | A taxa de cada conta é medida contra as transferências daquela conta |
A policy de conta continua vencendo a do tenant quando existir — o que muda entre as duas não é a unidade de contagem, apenas de onde saem os números.
A conta é a unidade porque é ela que o BACEN mede no bucket de rate limit do DICT: é nela que a rajada acontece e é nela que a punição chega. Somar as contas de um tenant produzia os dois erros ao mesmo tempo — uma conta parada herdava o consumo da vizinha, e num tenant grande o excesso de uma conta se diluía no total até nenhum limite fechar.
Pagamento por chave também consome cota
Esta seção descreve o comportamento que entrará em vigor. Hoje o pagamento por chave ainda não consome cota e não recebe 429 por esse motivo. Avisaremos com antecedência antes de ligar.
Um PIX Out no modo KEY precisa saber quem é o dono da chave antes de enviar o dinheiro. Essa resolução conta na mesma cota da consulta explícita, e por isso um pagamento pode receber 429 com errorCode: dict_lookup_limit_exceeded. Quando isso acontece, nenhum pagamento é criado: não há paymentId, não há transação, e reenviar com a mesma Idempotency-Key continua sendo seguro.
O cache de 24h é o que evita a dupla contagem. O fluxo mais comum — consultar a chave para exibir o destinatário e, confirmado pelo usuário, pagar — gasta uma consulta, não duas: a segunda é servida pelo cache. Quem paga direto, sem consultar antes, também gasta uma. Nos dois casos, 100 pagamentos por chave consomem cerca de 100 da cota, o que deixa o resto do orçamento para consultas avulsas.
O BigPix resolve a chave uma vez para o lote inteiro, independente de em quantas parcelas o valor é dividido.
Dois desfechos merecem atenção no POST de pagamento:
- Chave inválida ou inexistente devolve o erro na resposta, sem criar pagamento. É preferível a um pagamento que nasce e falha segundos depois.
- DICT indisponível (erro ou timeout do liquidante) não recusa nada: o pagamento segue e a chave é resolvida pelo liquidante, como antes. Indisponibilidade nossa ou dele não vira pagamento recusado nem consome cota.
O denominador da taxa de uso
A taxa de uso de uma janela é consultas ÷ transferências concluídas na mesma janela. Do lado do denominador entram só as transferências que de fato aconteceram, e só as daquela conta: COMPLETED e REFUNDED (que liquidaram e só depois foram devolvidas). Pagamento que falhou, foi recusado ou ficou indeterminado não amplia o teto — do contrário, quem estivesse repetindo uma tentativa com erro ganharia mais cota de consulta a cada falha.
Conta nova ou ociosa tem denominador zero, o que daria taxa infinita. Quem protege esse caso é o minLookups da janela: abaixo do piso de amostra nenhuma das duas regras pode recusar, então a conta faz suas primeiras consultas sem ser barrada por uma taxa que ainda não significa nada.
Até a v2.52.0 esse papel cabia a um piso global de 50 consultas/24h, ligado ao maxLookupRatio. Ele saiu junto com o limite; a mensagem (bootstrap floor of 50 lookups/24h applied) não aparece mais.
Ausente não é ilimitado
Um limite ausente na policy não significa ilimitado: vale o default global da tabela acima. Para remover o teto é preciso declarar isso explicitamente (opção No limit no Backoffice, que grava um valor negativo). Os limites de burst continuam ativos mesmo assim — remover o teto diário não libera rajada.
O que consome cota
Cota diária (maxLookupsPerDay) e ratio contam as consultas que chegaram ao DICT por vontade do integrador: chave encontrada, chave inexistente e chave recusada pelo DICT (requisição inválida, ou o limite do próprio DICT para aquele consultante). Falha técnica do liquidante e tentativa já recusada com 429 ficam de fora — não se deve queimar cota por indisponibilidade nossa, nem afundar mais fundo depois de já ter sido bloqueado. Vale igual para a consulta explícita e para a resolução feita dentro de um PIX Out.
Os limites de burst são o oposto: maxLookupsPerMinute conta todos os resultados, inclusive os recusados, porque a métrica ali é a pressão que o cliente está fazendo, não o proveito que tirou. maxNotFoundPer5min conta só as chaves inexistentes.
Cache de 24h
Consultas repetidas da mesma chave são servidas de um cache de 24h, e cache hit não consome cota. O cache é o mesmo para os dois caminhos: uma consulta explícita serve o pagamento seguinte, e a resolução feita dentro de um pagamento serve a consulta seguinte. Para forçar uma ida ao DICT — dados desatualizados, titularidade que pode ter mudado — use ?noCache=true na consulta explícita, lembrando que aí a consulta conta normalmente.
Webhook policy.violation
Toda violação — recusada ou apenas avisada — dispara o evento policy.violation para quem o assinou.
{
"phase": "edge",
"action": "BLOCK",
"blocked": true,
"accountId": "acc_...",
"identifier": "PEDIDO-1234",
"mode": "KEY",
"amount": 5000.00,
"violations": [
{ "rule": "maxAmount", "message": "amount R$ 5000.00 exceeds the per-transaction limit of R$ 1000.00" }
],
"counterparty": { "document": "12345678900", "name": "FULANO DE TAL" }
}
Em phase: "edge" não há paymentId: o gate roda antes de o pagamento ser criado, e é justamente por isso que a recusa cabe na resposta HTTP. Use o identifier para correlacionar. Na fase counterparty, que roda dentro do workflow, o paymentId já existe e vem no payload.
| Campo | Descrição |
|---|---|
phase | edge (na requisição), counterparty (após resolver o destinatário), pix_in (após o crédito) ou dict_lookup |
action | BLOCK, NOTIFY_ONLY, ALLOW_AND_NOTIFY ou AUTO_REFUND, conforme a configuração |
blocked | true quando a operação foi de fato recusada. Sempre false em pix_in |
violations | Todas as regras violadas, com o identificador em rule |
counterparty | O destinatário (PIX Out) ou o pagador (PIX In), quando conhecido |
Em phase: "pix_in" o payload troca paymentId por transactionId e endToEnd, e traz refunded indicando se o valor foi devolvido.
Detalhes de entrega, retentativas e assinatura no guia de Webhooks.
Visibilidade de Violações
- Webhook
policy.violation— em toda violação, em qualquer seção. - Timeline da transação (
GET /v1/transactions/{id}/timeline) — quando a violação recusa um PIX Out, o eventopix_out.failedtrazerrorCode: policy_deniede as regras violadas empolicyViolations. Numa recusa na borda, em que ainda não existepaymentId, a âncora do evento é oworkflowIddeterminístico da operação, que é o mesmo id devolvido nas respostas de PIX out. O endpoint aceita os dois, além deendToEndId,txide o id do parceiro. - Painel — a aba Violations lista o histórico, separando o que foi barrado, o que foi só avisado e o que foi devolvido, com o total por regra.
Uma operação recusada por política nunca chega ao banco parceiro, e o extrato (GET /v1/accounts/{accountId}/statement) reflete o que aconteceu na conta. Violações não aparecem lá. Use o webhook, a timeline ou o painel. A exceção é a devolução de um PIX In por AUTO_REFUND: ela é uma movimentação de verdade e aparece no extrato como devolução.
A allowlist de IP que de fato bloqueia tráfego é a do WAF, configurada na tela de Security — não é uma política. Controles de MED têm guia próprio em Disputas (MED).