GUIA DE INTEGRAÇÃO

Como integrar Pix com Node.js: do pedido à confirmação

A integração Pix tem duas partes: criar a cobrança e reconhecer o pagamento com segurança. Este guia usa Node.js 22 ou superior, fetch nativo e a API REST do Calebe Pay para conectar as duas etapas ao pedido salvo no seu sistema.

Para desenvolvedores de SaaS, e-commerce e sistemas próprios

Atualizado em

1. Prepare o backend e uma chave de teste

Comece com uma chave cp_test_ criada no portal, com as permissões pix:write e transactions:read. Guarde o segredo em CALEBE_API_KEY no servidor. O navegador ou aplicativo conversa com o seu backend; a chave da API não deve aparecer no bundle, no localStorage ou em variáveis públicas.

A chave escolhe o ambiente. Com cp_test_, a mesma rota POST /v1/pix gera uma transação simulada, sem cobrança real e sem envio ao provedor. A resposta deve trazer livemode: false, simulated: true e environment: sandbox. O código retornado nesse modo não é pagável.

2. Salve o pedido antes da chamada

No banco da sua aplicação, grave o pedido, uma chave de idempotência exclusiva para a tentativa e o payload exato da cobrança. Isso deve acontecer antes da rede: se a conexão cair, sua aplicação precisa conseguir recuperar a tentativa original.

O valor é um inteiro em centavos: amount: 1250 representa R$ 12,50. Envie reference, description e o customer com nome, documento, e-mail, telefone e endereço completo. O endereço inclui CEP, logradouro, número, bairro, cidade e UF. Para Pix, expires_in define a validade em segundos, entre 60 e 86400; o padrão é 3600.

Use os dados legítimos do pagador em produção. O JSON de exemplo da documentação contém dados fictícios para simulação; ele não deve preencher campos ausentes de um cliente real.

  • Idempotency-Key aceita de 1 a 128 caracteres: letras ASCII, números, ponto, hífen, dois-pontos e sublinhado.
  • Uma referência como pedido-42 ajuda a localizar a venda, mas não substitui a chave de idempotência e não é necessariamente única.
  • A conta de emissão vem da API key. Não envie tenant_id, provider_id ou instruções de split no corpo público.

3. Envie o pedido salvo com fetch

Esta função deve rodar somente no backend. Ela recebe a chave de idempotência e o payload que sua aplicação já persistiu. O exemplo exige uma chave de teste deliberadamente, usa um limite de espera de 30 segundos e recusa redirecionamentos com credenciais.

Depois de receber a resposta, salve transaction.id no mesmo pedido antes de apresentar a cobrança ao usuário. O exemplo não cria chaves novas nem repete a chamada automaticamente. Ele também não interpreta uma resposta HTTP de sucesso como pagamento confirmado.

Node.js 22+ · emitir-pix.mjs
const apiKey = process.env.CALEBE_API_KEY;
if (!apiKey?.startsWith('cp_test_')) {
  throw new Error('Use uma chave de teste neste exemplo.');
}

// payload e idempotencyKey já estão salvos no pedido.
export async function emitirPix({ payload, idempotencyKey }) {
  if (!payload || !idempotencyKey) {
    throw new Error('Recupere os dados persistidos do pedido.');
  }
  const response = await fetch('https://api.calebepay.com.br/v1/pix', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': apiKey,
      'Idempotency-Key': idempotencyKey,
    },
    body: JSON.stringify(payload),
    signal: AbortSignal.timeout(30_000),
    redirect: 'error',
  });
  const result = await response.json();
  if (!response.ok) {
    const error = new Error(result.error?.code ?? 'api_error');
    error.transactionId = result.error?.transaction_id;
    throw error;
  }
  return { httpStatus: response.status, transaction: result.data };
}

4. Diferencie emissão, incerteza e pagamento

Uma nova emissão conhecida retorna HTTP 201. Um replay pode retornar 200 com Idempotency-Replayed: true. Uma resposta 202 indica processamento ou resultado incerto. Em todos esses casos, leia o status da transação; nenhum desses códigos HTTP, sozinho, confirma pagamento.

Os campos pix_copy_paste e pix_qr_code podem ser nulos em uma resposta parcial. Espere um instrumento disponível e válido antes de mostrá-lo. O document_url é o endereço da cobrança que pode ser apresentado ao pagador; trate esse link como um documento que contém dados da cobrança.

Se ocorrer timeout ou falha de conexão, mantenha o payload e a chave originais. Consulte GET /v1/transactions/{id} quando conhecer o ID ou recupere o registro repetindo o mesmo POST. Não gere uma cobrança nova só porque a resposta não chegou. Uma tentativa failed também continua vinculada à chave anterior.

SituaçãoTratamento no sistema
pending / processingAcompanhar a tentativa; ainda não liberar o pedido.
unknown ou timeoutReconciliar o resultado existente, sem trocar automaticamente a chave.
409 idempotency_conflictRecuperar método, corpo e chave originais da tentativa.
paid em testeValidar a integração; não representa dinheiro recebido.

5. Confirme o Pix pelo webhook e pela conciliação

Cadastre no portal um endpoint de teste para receber transaction.updated. Antes de confiar no evento, valide Calebe-Signature com HMAC-SHA256 sobre o timestamp e os bytes originais do corpo, usando o segredo de webhook da conta. Confira a tolerância de horário e compare a assinatura em tempo constante.

Persista o evento antes de responder 2xx e use seu id para reconhecer repetições. Entregas podem chegar novamente ou fora de ordem. Para consultar o estado atual, use GET /v1/transactions/{id}; mantenha uma rotina limitada de conciliação no backend e use POST /v1/transactions/{id}/refresh quando precisar consultar o provedor.

No teste, POST /v1/transactions/{id}/simulate com status paid ou expired permite validar a mudança de uma cobrança pendente e seu webhook. A liberação de uma venda real exige status paid junto de livemode: true, environment: production e simulated: false, conferidos pelo backend.

6. Passe para produção com a conta habilitada

A URL e o contrato da API permanecem iguais. A passagem à produção exige liberação da conta, chave de produção no servidor e endpoints de webhook no modo correto. A restrição cp_test_ do exemplo precisa ser revisada conscientemente na implementação de produção.

Mantenha os registros de teste separados dos pedidos reais, confirme o ambiente de cada resposta e acompanhe eventuais recusas no monitor de integração. Uma resposta live_payments_disabled indica que a produção ainda não está liberada; trocar a chave de idempotência não resolve essa autorização.

API REST · PIX E BOLETO · AMBIENTE DE TESTE

Conecte a cobrança ao seu sistema.

Criar minha conta →Ver todos os guias →