Pular para o conteúdo
xFlow Payments

Blog

Segurança na integração da API Pix

Uma integração segura com a API Pix guarda o segredo só no servidor, limita as chamadas por IP, troca as credenciais sem parar a operação, valida a assinatura HMAC de todo webhook e registra o request_id de cada chamada. Abaixo, cada controle da xFlow e o que fica do seu lado.

Atualizado em · Equipe xFlow Payments · 6 min de leitura

A segurança de uma integração com a API Pix depende de cinco pontos: onde o segredo fica guardado, de onde as chamadas podem sair, como as credenciais são trocadas, como o seu sistema confia nos webhooks e o que fica registrado de cada chamada. A xFlow oferece controles para cada um. O resto é código e processo do seu lado. A visão institucional dos controles está na página de segurança da xFlow; aqui está o que fazer na integração.

Credenciais: onde o segredo pode ficar

A API usa HTTP Basic: a chave pública (pk_live_) é o usuário e o segredo (sk_live_) é a senha. A chave pública fica sempre visível no painel. O segredo aparece uma única vez, na criação.

  • Guarde o segredo no servidor, num cofre de segredos ou numa variável de ambiente.
  • Nunca no navegador nem no app. Código de front-end e pacotes de aplicativo podem ser inspecionados.
  • Nunca no repositório. Nem em arquivo de exemplo, nem em histórico de commits. Se um segredo foi commitado, trate como vazado.
  • Nunca nos logs. Não registre o header Authorization.
  • Teste e produção separados. Chaves pk_test_ e sk_test_ usam os mesmos endpoints num ambiente separado, e toda resposta traz livemode. Use variáveis diferentes por ambiente e confira o livemode antes de dar baixa num pedido.

A documentação também aceita o formato legado Authorization: Bearer sk_live_.... Para uma integração nova, siga o formato principal, com Basic.

Allowlist de IP

No painel, em Chaves de API, você pode limitar as chamadas a uma lista de IPs. Fora da lista, a resposta é 401, mesmo com a credencial correta. Isso reduz o estrago de um segredo vazado: quem tem o segredo, mas não está nos seus servidores, não consegue chamar a API.

Dois cuidados práticos:

  1. Liste os IPs de saída dos servidores que chamam a API. Em ambientes com IP variável, use uma saída com IP fixo.
  2. Ao mudar a infraestrutura, atualize a lista antes da troca. Um 401 logo depois de uma mudança de servidor costuma ser IP fora da lista.

Troca de credenciais sem parar a operação

O painel permite criar e revogar credenciais em Desenvolvedores > Chaves de API, e a revogação é imediata. Para trocar sem derrubar as cobranças:

  1. Crie uma credencial nova.
  2. Grave o segredo novo no cofre.
  3. Publique a mudança nos servidores.
  4. Confira em Integrações > Logs da API que as chamadas seguem com sucesso.
  5. Revogue a credencial antiga.

Troque quando alguém com acesso ao segredo sair da equipe, quando houver suspeita de vazamento e numa rotina definida pela sua política. Em caso de vazamento, inverta a ordem: revogue primeiro e depois publique a credencial nova.

A documentação não descreve permissões por credencial. Trate toda credencial da conta como capaz de chamar todos os endpoints, inclusive o de saque, e restrinja quem tem acesso a ela.

Webhooks: confie só no que está assinado

Cada entrega traz o header x-webhook-signature: sha256=<hex>, o HMAC-SHA256 do corpo cru com o segredo do endpoint. O handler deve:

  • calcular o HMAC sobre o corpo cru, antes de qualquer JSON.parse;
  • comparar em tempo constante e recusar o que não bater;
  • conferir livemode e o valor antes de liberar o pedido;
  • processar cada evento uma vez só, porque o mesmo evento pode chegar até 3 vezes de novo.
js
import { createHmac, timingSafeEqual } from "node:crypto";

function assinaturaValida(raw, header, segredo) {
  const esperado = "sha256=" + createHmac("sha256", segredo).update(raw).digest("hex");
  const a = Buffer.from(esperado), b = Buffer.from(header ?? "");
  return a.length === b.length && timingSafeEqual(a, b);
}

O segredo do endpoint também aparece uma única vez, na resposta de POST /api/v1/webhooks. A API não documenta a troca de segredo de um endpoint existente. Para trocar, crie um endpoint novo, publique o segredo novo no handler e apague o antigo com DELETE /api/v1/webhooks/{id}. Enquanto os dois existirem, o mesmo evento pode chegar duas vezes, e a idempotência do handler resolve. O handler completo está em webhook Pix, e o validador de assinatura ajuda a depurar quando o HMAC não bate.

Dados pessoais nas respostas

A cobrança traz customer (o que você informou) e, depois do pagamento, payer: nome, CPF ou CNPJ e banco de quem pagou. Os documentos vêm completos, só com dígitos, nas respostas e nos webhooks. Mascare esses campos nos seus logs, limite quem consulta os registros e guarde só o que a operação precisa, de acordo com a sua política de privacidade.

Duplicidade e abuso

  • Idempotency-Key. Envie uma chave única por cobrança e por saque. Na repetição com o mesmo corpo, a API devolve o mesmo recurso. Com outro corpo, 409 idempotency_conflict. Veja idempotência em API de pagamento.
  • Limite de requisições. O limite é por conta. Toda resposta autenticada traz x-ratelimit-limit, x-ratelimit-remaining e x-ratelimit-reset, e acima do limite a resposta é 429 com retry-after.
  • Proteja o seu endpoint de criar cobrança. Se qualquer visitante consegue gerar cobranças no seu site sem limite, um robô consome o limite da sua conta. Ponha limite e validação no seu back-end.
  • Limites de valor. Cada conta tem valor mínimo e máximo por cobrança, em Empresa > Limites e taxas.

Saque: o endpoint mais sensível

POST /api/v1/transfers tira dinheiro do saldo. Proteja esse caminho mais do que os outros:

  • Aprovação. Com o saque automático desligado na conta, cada saque pela API nasce com pending_approval: true.
  • Saque via API desabilitado. Quando o saque via API está desabilitado para a conta, a resposta é 403 api_withdrawal_disabled. Se a sua integração não precisa sacar, pergunte ao suporte se esse pode ser o caso da sua conta.
  • Alçada interna. A API envia o que o seu sistema mandar. Quem pede o saque não deveria ser quem aprova.

Registro de cada chamada

Toda resposta traz um request_id (req_...), no corpo e no header x-request-id. Em Integrações > Logs da API, cada requisição autenticada aparece com status, duração e código de erro, por 30 dias. Guarde o request_id nos seus logs. Nos seus próprios registros, fique de olho em picos de 401: podem ser uma credencial errada num deploy ou alguém tentando usar uma chave que não funciona mais. A lista de códigos está em erros da API Pix.

Checklist

  1. Segredo só no servidor, fora do repositório e fora dos logs.
  2. Variáveis separadas para teste e produção, e livemode conferido.
  3. Allowlist de IP com os IPs de saída dos servidores.
  4. Procedimento escrito para trocar e revogar credenciais.
  5. HMAC validado sobre o corpo cru, em tempo constante.
  6. Handler de webhook idempotente.
  7. Idempotency-Key em toda cobrança e todo saque.
  8. Documentos de pagadores mascarados nos logs.
  9. Saque com aprovação ou desabilitado quando não for usado.
  10. request_id registrado em toda chamada.

A referência de autenticação, webhooks e erros está na documentação da API.

Perguntas frequentes

Posso colocar a chave da API Pix no front-end ou no aplicativo?

Não. O segredo (sk_live_) dá acesso à conta e precisa ficar no servidor, num cofre de segredos ou numa variável de ambiente. O navegador e o app falam com o seu back-end, que chama a API.

Como trocar a chave da API sem parar a operação?

Crie uma credencial nova no painel, publique no servidor, confirme nos Logs da API que as chamadas seguem com sucesso e só então revogue a antiga. A revogação tem efeito imediato.

Por que a API responde 401 se a credencial está certa?

Se a allowlist de IP estiver configurada, chamadas de IPs fora da lista recebem 401 mesmo com a credencial correta. Confira se o IP de saída do servidor mudou.

Como saber se um webhook veio mesmo da xFlow?

Calcule o HMAC-SHA256 do corpo cru com o segredo do endpoint, prefixe com sha256= e compare, em tempo constante, com o header x-webhook-signature. Se não bater, recuse o evento.

Continue lendo

SegurançaNa xFlow, todo pagamento é conferido na adquirente antes de cair no saldo, o segredo da chave de API aparece uma única vez, credenciais podem ser revogadas na hora e limitadas por IP, webhooks são assinados e cada chamada fica registrada nos Logs da API.BlogWebhook Pix: eventos, assinatura HMAC e boas práticasWebhook Pix é o aviso que a API envia para a sua URL quando algo acontece com uma cobrança ou um saque, como o pagamento confirmado. Na xFlow, cada aviso é um POST JSON assinado com HMAC-SHA256, reenviado até 3 vezes até você responder 2xx.BlogErros da API PixNa API Pix da xFlow, todo erro volta em JSON com error (o código), message e request_id. O status HTTP diz a família do problema: 400 corpo inválido, 401 credencial, 403 conta ou modo, 404 recurso inexistente, 409 idempotência, 422 recusa de negócio, 429 limite e 502 falha no provedor. O request_id localiza a chamada em Integrações > Logs da API.BlogIdempotência em API de pagamento: retry sem duplicarIdempotência é a garantia de que repetir a mesma requisição não repete o efeito. Na API da xFlow, você envia o header Idempotency-Key ao criar cobranças e saques: num retry com a mesma chave, a API devolve a mesma cobrança ou o mesmo saque, sem gerar outro Pix nem debitar o saldo de novo.FerramentaValidador de assinatura de webhookInforme o segredo do endpoint, o corpo cru da requisição e o valor do header x-webhook-signature. A página calcula o HMAC-SHA256 como o seu servidor deveria calcular e diz se a assinatura confere.