Pular para o conteúdo
xFlow Payments

Blog

Cobrança Pix expirada

Na API da xFlow, cobrança Pix expirada é a que passou ao status expired: expirou sem pagamento. Não há webhook de expiração, então você detecta pela consulta ou pela listagem com status=expired e, se o cliente ainda quiser pagar, cria uma cobrança nova para o mesmo pedido, com outra Idempotency-Key.

Atualizado em · Equipe xFlow Payments · 5 min de leitura

Cobrança Pix expirada, na API da xFlow, é a cobrança que passou ao status expired: o prazo acabou e ninguém pagou. A documentação não traz um jeito de reativá-la, e não existe webhook avisando da expiração. O seu sistema descobre consultando a cobrança e, se o cliente ainda quiser pagar, cria uma cobrança nova para o mesmo pedido. Quem cuida disso direito evita duas falhas comuns: mostrar ao cliente um QR Code que já não vale e gerar cobranças em dobro para o mesmo pedido.

O que significa expired

A cobrança nasce pending e muda conforme o pagamento. Estes são os status documentados:

Status Significado O que fazer no pedido
pending Aguardando pagamento Mostrar o QR Code e o copia e cola
paid Pago e confirmado; o líquido entra no saldo Liberar o pedido
expired Expirou sem pagamento Oferecer um código novo
canceled Cancelada Não reaproveitar; criar outra se for o caso
under_review Em análise Esperar; não liberar o pedido
blocked Bloqueada Não liberar; verificar com o suporte
refunded Estornada Tratar como venda desfeita

A diferença que importa: expired quer dizer que o cliente não pagou a tempo. Não houve erro, recusa nem bloqueio. É o caso mais simples de recuperar.

Quanto tempo a cobrança vale

A documentação da xFlow não traz um parâmetro para definir a validade da cobrança nem informa um prazo padrão. Por isso, não monte um contador regressivo com um prazo inventado. Se a sua tela precisa dizer algo, diga que o código vale por tempo limitado e confira o status antes de agir. A diferença entre QR Code estático e dinâmico, e onde o prazo aparece no padrão do Pix, está em QR Code Pix dinâmico por API.

Como detectar a expiração sem webhook

Como não há evento de expiração, use consulta em dois momentos:

  1. Quando o cliente volta. Antes de mostrar um QR Code salvo, chame GET /api/v1/charges/{id}. Se vier expired, não mostre o código antigo.
  2. Numa varredura periódica. Um job lista as cobranças expiradas do período e atualiza os pedidos que ainda estão como aguardando pagamento.

A listagem aceita status, from e to e pagina por cursor:

js
const BASE = "https://app.xflowpayments.com/api/v1";
const AUTH = "Basic " + Buffer.from(
  `${process.env.XFLOW_PUBLIC_KEY}:${process.env.XFLOW_SECRET_KEY}`,
).toString("base64");

async function marcarExpiradas(de, ate) {
  let cursor;
  do {
    const url = new URL(`${BASE}/charges`);
    url.searchParams.set("status", "expired");
    url.searchParams.set("from", de); // ex.: 2026-10-24
    url.searchParams.set("to", ate);  // ex.: 2026-10-25
    url.searchParams.set("limit", "100");
    if (cursor) url.searchParams.set("starting_after", cursor);

    const res = await fetch(url, { headers: { Authorization: AUTH } });
    if (!res.ok) throw new Error(`listagem falhou: ${res.status} ${res.headers.get("x-request-id")}`);
    const { data, has_more } = await res.json();

    for (const cobranca of data) {
      await marcarPedidoComoExpirado(cobranca.external_reference, cobranca.id); // a sua regra
    }
    cursor = has_more ? data[data.length - 1].id : undefined;
  } while (cursor);
}

Cada página tem de 1 a 100 itens (limit). Enquanto has_more vier true, repita com starting_after igual ao id do último item. A varredura conta no limite de requisições da conta, então rode em intervalos, não em loop contínuo.

Gerar uma cobrança nova para o mesmo pedido

Quando o cliente quer pagar depois da expiração, crie outra cobrança. Dois campos decidem se isso dá certo:

  • Idempotency-Key nova. Com a chave antiga e o mesmo corpo, a API devolve a cobrança anterior, que está expirada. Com a chave antiga e outro corpo, responde 409 idempotency_conflict. Use um sufixo de tentativa, como pedido-1234-2.
  • O mesmo external_reference. Ele não precisa ser único. Com o mesmo id do pedido, todas as tentativas aparecem juntas em GET /api/v1/charges?external_reference=pedido-1234.
bash
curl -X POST https://app.xflowpayments.com/api/v1/charges \
  -u "pk_live_...:sk_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-1234-2" \
  -d '{
    "amountCents": 1990,
    "customer": { "name": "Cliente Exemplo", "email": "cliente@exemplo.com", "document": "00000000000" },
    "description": "Pedido #1234 (nova tentativa)",
    "external_reference": "pedido-1234"
  }'

No seu banco, guarde a lista de cobranças de cada pedido e marque qual é a vigente. A regra de idempotência completa está em idempotência em API de pagamento.

Pagamento em mais de uma tentativa

Com várias cobranças para o mesmo pedido, o seu handler de transaction.paid precisa achar o pedido pelo external_reference e pelo id da cobrança paga, e não só pela cobrança vigente. Se duas cobranças do mesmo pedido chegarem como pagas, por exemplo porque o cliente pagou uma tentativa e depois a outra, o pedido foi pago duas vezes. Nesse caso, devolva uma delas com POST /api/v1/charges/{id}/refund. O estorno é total, uma vez por cobrança, até 90 dias depois do pagamento. O fluxo está em estorno Pix por API.

Para confirmar qualquer pagamento, a regra é a mesma de sempre: webhook assinado primeiro, consulta como reserva. Veja como saber se o Pix foi pago pela API.

O que mostrar ao cliente

  • Mensagem clara. "Este código Pix expirou" e um botão "Gerar novo código".
  • Código novo só quando o cliente pede. Não crie cobranças em loop enquanto a página está aberta: cada uma é uma cobrança nova e conta no limite de requisições.
  • Código antigo escondido. Tire da tela o QR Code e o copia e cola que expiraram.
  • Celular primeiro. Na tela nova, o botão de copiar o código continua sendo o caminho principal para quem paga pelo próprio celular.

Erros comuns

  • Confiar no QR salvo. O pedido guardou pix.copyPaste ontem; hoje a cobrança está expired. Sempre consulte antes de reexibir.
  • Reusar a Idempotency-Key. A API devolve a cobrança expirada de novo, e o cliente recebe um código que não vale.
  • Esperar um webhook que não existe. Sem varredura, o pedido fica para sempre como aguardando pagamento.
  • Buscar o código na listagem. A listagem não traz pix.copyPaste nem pix.qrCodeBase64. Para mostrar o código de uma cobrança, use GET /api/v1/charges/{id}.

Os status e os parâmetros da listagem estão na documentação da API. Os eventos que existem estão no guia de webhook Pix.

Perguntas frequentes

Existe webhook de cobrança Pix expirada?

Não. Os eventos de cobrança são transaction.pending, transaction.paid, transaction.refunded e transaction.refund_failed. Para saber se uma cobrança expirou, consulte GET /api/v1/charges/{id} ou liste com GET /api/v1/charges?status=expired.

Posso reativar uma cobrança expirada?

A documentação não traz endpoint para reativar cobrança. Se o cliente ainda quiser pagar, crie uma cobrança nova para o mesmo pedido, com uma Idempotency-Key nova.

Posso usar o mesmo external_reference na cobrança nova?

Sim. O external_reference não precisa ser único. Usar o mesmo id do pedido faz todas as tentativas aparecerem juntas em GET /api/v1/charges?external_reference=.

Como definir o prazo de expiração da cobrança?

A documentação da xFlow não traz parâmetro para definir a validade nem informa um prazo padrão. Trate o status devolvido pela API como a fonte da verdade.

Continue lendo

BlogQR Code Pix dinâmico por API: estático x dinâmicoPara gerar um QR Code Pix por cobrança via API na xFlow, chame POST /api/v1/charges: cada cobrança volta com um QR Code próprio em PNG (pix.qrCodeBase64), o copia e cola (pix.copyPaste), o valor do pedido e um status que muda até o pagamento.BlogComo saber se o Pix foi pago pela APIPara saber se um Pix foi pago pela API da xFlow, assine o webhook transaction.paid e, como reserva, consulte GET /api/v1/charges/{id} até o status sair de pending. Só libere o pedido com status paid, assinatura válida, livemode: true e valor igual ao do pedido.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.BlogEstorno Pix por APINa API da xFlow, o estorno Pix é um POST /api/v1/charges/{id}/refund que devolve ao pagador o valor total de uma cobrança paga, uma vez por cobrança e até 90 dias após o pagamento. A devolução é assíncrona: a resposta 202 diz que o PSP aceitou o pedido, e a conclusão chega pelo webhook transaction.refunded.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.