Pix2DePix

Boas práticas

O que separa uma integração que passa no teste de uma que aguenta produção.

1. Mande sempre o externalId

É o número do pedido no seu sistema, e é o que torna a criação idempotente.

POST /v1/charges  {"externalId": "pedido-8891", …}

Se a resposta se perder — timeout, deploy no meio, cliente que clicou duas vezes — repetir a mesma requisição devolve a mesma cobrança, com 200 em vez de 201. Sem externalId, cada requisição cria um QR novo, e o seu cliente fica com dois QRs para o mesmo pedido.

Se o corpo for diferente com o mesmo externalId, a resposta é 409 external_id_conflict — dois pedidos disputando um número é bug seu, e é melhor descobrir na hora.

Para o retry cego de uma biblioteca de HTTP, mande também o cabeçalho Idempotency-Key com um UUID por tentativa lógica.

2. Deduplique pelo id do evento

A entrega do webhook é at-least-once. Guarde event.id numa tabela com chave única e ignore o que já processou. Isto não é opcional: reenvio manual do painel e retentativa nossa produzem o mesmo evento duas vezes de propósito.

3. Confirme por GET antes de liberar produto

O webhook chega antes, mas é um POST na sua URL pública. Depois de validar a assinatura, confirme o estado com GET /v1/charges/{id} e decida em cima da resposta.

Uma requisição a mais por venda é barato perto de liberar produto por um evento que não era nosso.

4. Trate o atraso de liquidação

Este é o ponto que mais dá problema em integração nova.

Pix pago  ──── até 24h ────►  DePix na sua carteira
     │                              │
paid_pending_settlement          settled
  • Não libere produto em paid_pending_settlement. O dinheiro saiu do banco do seu cliente, mas ainda não é seu.
  • Mostre settlement.estimatedAt na tela do pedido: é a data em que o DePix deve sair, e é o que evita o chamado "paguei e não recebi".
  • Se você vende algo instantâneo (jogo, crédito, assinatura), decida conscientemente se assume o risco de liberar antes — e assuma sabendo que charge.refunded existe.

5. Nunca confie só no webhook

Endpoint fora do ar, deploy no meio da tarde, firewall que bloqueou nosso IP: tudo isso acontece. Tenha uma rede de segurança:

  • uma rotina que roda de tempos em tempos e consulta GET /v1/charges?status=paid_pending_settlement para achar o que ficou para trás;
  • e o mesmo para pedidos seus que estão abertos há mais tempo que o esperado.

6. Guarde o requestId de todo erro

Toda resposta de erro traz error.requestId. Grave no seu log junto do pedido. É por ele que o suporte acha a requisição — sem ele, a investigação começa por "mais ou menos que horas foi?".

7. Repita o que dá para repetir

  • 429 — respeite o Retry-After.
  • 409 charge_processing — repita em 1 segundo.
  • 503 e 5xx — espera crescente.
  • 4xx em geral — não repita igual; corrija.

Ver a tabela de erros.

8. A chave é segredo de servidor

  • Nunca no navegador, nunca em app mobile, nunca no repositório.
  • Uma chave por integração, com nome que diga qual é: revogar a da loja antiga não pode derrubar a nova.
  • Rotacione trocando: crie a nova, publique, confirme que rodou, revogue a velha. O painel mostra o último uso de cada uma.
  • O segredo do webhook é outro e tem outra função: a chave de API prova que é você chamando; o segredo do webhook prova que somos nós chamando. Vazar um não pode entregar o outro.

9. Teste no sandbox o que dói em produção

A chave p2d_test_ roda o ciclo inteiro sem dinheiro. Exercite antes de ligar:

  • o que a sua tela mostra em paid_pending_settlement;
  • o seu código de validação de assinatura, com POST /v1/webhooks/test;
  • o caminho de charge.expired e o de charge.refunded;
  • o seu deduplicador, reenviando a mesma entrega pelo painel duas vezes.

10. Cancelou? Tire o QR da tela

POST /v1/charges/{id}/cancel fecha a cobrança do nosso lado, mas o QR Code já emitido continua tecnicamente pagável — nosso provedor de Pix não tem como invalidá-lo.

Se o seu cliente pagar assim mesmo, o pagamento vence: a cobrança volta a andar e você recebe charge.paid_pending_settlement. Trate esse caso, e sobretudo tire o QR da frente dele ao cancelar.