Acompanhar reembolsos e chargebacks

Receba o pedido de reembolso, consulte os pedidos na API e reaja ao estorno e ao chargeback de uma venda.

Use este guia depois que a venda foi paga. Ele mostra como saber quando o cliente pede o dinheiro de volta, quando o estorno acontece e quando o banco do cliente contesta a compra.

A API consulta os pedidos de reembolso e reembolsa uma venda sua. Aceitar, recusar ou cancelar um pedido aberto pelo cliente é feito no painel da PagPolar.

Se a venda é de uma assinatura, o reembolso, o estorno e o chargeback também cancelam a assinatura. Veja em quais casos.

Visão geral

O diagrama mostra o caminho mais comum: o cliente pede o reembolso, você aceita no painel e o gateway devolve o dinheiro.

Antes de começar

O que fica na API e o que fica no painel

O que aconteceOnde
O cliente pede reembolso.Na PagPolar. Você recebe TRANSACTION_ASK_REFUNDING.
Aceitar, recusar ou cancelar o pedido do cliente.Tela Reembolsos do painel. Não existe rota na API para isso.
Reembolsar uma venda por sua conta, sem pedido do cliente.POST /refunds
Ver os pedidos e a situação de cada um.GET /refunds
Saber que o dinheiro voltou para o cliente.TRANSACTION_REFUNDED
Saber que o banco do cliente contestou a compra.TRANSACTION_CHARGEBACK_APPROVED

Passo a passo

Receba o pedido de reembolso

Quando o cliente pede reembolso, a PagPolar envia TRANSACTION_ASK_REFUNDING para o seu webhook. O dinheiro ainda não voltou para o cliente.

Exemplo resumido do que chega. O payload completo está em TRANSACTION_ASK_REFUNDING.

{
  "event": "TRANSACTION_ASK_REFUNDING",
  "data": {
    "transaction": {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "identifier": "PPO9876543210",
      "status": "ASK_REFUND",
      "payment_method": "PIX",
      "total_amount": "197.0000",
      "refund_reason": "Produto não atendeu às expectativas",
      "refund_at": null
    }
  }
}

O status da venda diz o tipo de pedido:

data.transaction.statusTipo de pedido
ASK_REFUNDReembolso da venda inteira.
ASK_PARTIAL_REFUNDReembolso de parte dos itens da venda.

Faça assim:

  1. Grave o pedido junto da venda, usando o data.transaction.id.
  2. Guarde o data.transaction.identifier. É o código da venda, com o prefixo, como PPO9876543210: o mesmo valor da API. Use esse valor no filtro sale_identifier do próximo passo.
  3. Não revogue o acesso ainda. Espere TRANSACTION_REFUNDED.

Pedido aberto pelo vendedor não envia este evento

Quando o pedido é aberto pelo próprio vendedor, pela PagPolar ou por POST /refunds, ele já nasce aceito e TRANSACTION_ASK_REFUNDING não é enviado. Para ver esses pedidos, consulte GET /refunds. Os abertos no painel aparecem com requested_by: "SELLER".

Consulte o pedido na API

Chame GET /refunds com o código da venda no filtro sale_identifier.

curl "https://api.pagpolar.com/v1/refunds?sale_identifier=PPO9876543210" \
  -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>"
const apiUrl = 'https://api.pagpolar.com/v1';
const accessToken = '<SEU_TOKEN_DE_ACESSO>';
const saleIdentifier = 'PPO9876543210';

const query = new URLSearchParams({ sale_identifier: saleIdentifier });

const response = await fetch(`${apiUrl}/refunds?${query}`, {
  headers: { Authorization: `Bearer ${accessToken}` },
});

if (!response.ok) {
  throw new Error(`Erro ${response.status}: ${await response.text()}`);
}

const body = await response.json();

for (const refund of body.data) {
  console.log(refund.id, refund.status, refund.is_partial, refund.refund_amount);
}

Resposta resumida. Todos os campos estão na referência de GET /refunds.

{
  "data": [
    {
      "id": "3c9f1e2a-7b4d-4e8a-9f10-2b3c4d5e6f70",
      "status": "PENDING",
      "requested_by": "CLIENT",
      "is_partial": false,
      "refund_amount": null,
      "reason": "Não atendeu às expectativas",
      "refused_reason": null,
      "canceled_reason": null,
      "return_tracking": null,
      "sale": {
        "identifier": "PPO9876543210",
        "status": "ASK_REFUND",
        "payment_method": "PIX",
        "total_amount": 197
      },
      "created_at": "2026-09-15T13:00:00.000Z",
      "updated_at": "2026-09-15T13:00:00.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "total_pages": 1
  }
}
CampoO que significa
idId do pedido de reembolso.
statusSituação do pedido. Veja Situações do pedido de reembolso.
requested_byQuem abriu o pedido: CLIENT (o cliente) ou SELLER (o vendedor ou a PagPolar).
is_partialtrue quando o pedido é de parte dos itens.
refund_amountValor do reembolso parcial, em reais, como número: 49.9 = R$ 49,90. null no reembolso da venda inteira.
reasonMotivo informado no pedido.
refused_reasonMotivo da recusa. null se não foi recusado.
canceled_reasonMotivo do cancelamento. null se não foi cancelado.
return_trackingRastreio da devolução de produto físico. null quando não há rastreio.
saleResumo da venda: identifier, status, payment_method e total_amount.
customerO cliente, com documento e telefone mascarados.

Filtros aceitos:

ParâmetroO que faz
sale_identifierTraz só os pedidos da venda com esse código.
statusTraz só os pedidos nessa situação.
created_from e created_toTraz os pedidos criados nesse intervalo. Data e hora em ISO 8601 com fuso.
page e per_pagePaginação. Veja Paginação e filtros.

Use o código da venda, não o id

sale_identifier procura pelo código da venda (identifier). Ele aceita o código como chega no webhook e na API, com o prefixo, como PPO9876543210, o código só com os 10 dígitos, como 9876543210, e um link que termina no código. Um id (uuid) nesse filtro não encontra nada.

O bloco sale não traz o id da venda. Para ver a venda completa, chame GET /sales/{identifier} com o sale.identifier.

Uma venda só tem um pedido em andamento por vez. Depois que um pedido termina (reembolsado, recusado, cancelado ou com falha), um novo pedido pode ser aberto. Por isso, o filtro pode trazer mais de um pedido para a mesma venda.

Acompanhe a decisão no painel

O vendedor responde ao pedido no painel. Nenhuma decisão envia evento de webhook, nem quando a venda volta para PAID. Consulte GET /refunds para saber o que aconteceu. Veja Ciclo de vida da venda.

No painel, os pedidos ficam em Vendas → Reembolsos, com os indicadores por situação e a lista de pedidos:

Tela Reembolsos do painel, com os indicadores Aguardando aprovação, Aprovados, Negados e Aguardando código, as abas por situação e a lista de pedidos

Ao abrir um pedido, a tela Detalhes do reembolso mostra a situação, a compra, o motivo informado pelo cliente e, quando houver, a data e o motivo da recusa. É nessa tela que o vendedor aceita ou recusa um pedido pendente:

Tela Detalhes do reembolso com um pedido recusado, mostrando o resumo da compra, o motivo do cliente e o motivo da recusa

DecisãoSituação do pedidoStatus da vendaEvento
Aceito pelo vendedorACCEPTED, depois REFUNDINGVenda inteira: REFUNDING. Parte dos itens: não muda.Nenhum
Aceito pela PagPolarACCEPTED_BY_ADMIN, depois REFUNDINGIgual ao aceito pelo vendedor.Nenhum
RecusadoREFUSED ou REFUSED_BY_ADMINSe estava em ASK_REFUND ou ASK_PARTIAL_REFUND, volta para PAID. Em outro status, não muda.Nenhum
CanceladoCANCELEDVolta para PAID.Nenhum
O gateway recusou o estornoFAILEDVenda inteira: volta para ASK_REFUND.Nenhum

Na recusa do pedido da venda inteira, o repasse e a taxa ligados à venda também voltam para PAID. Para saber se o pedido foi recusado ou cancelado, use o status do pedido em GET /refunds, e não o status da venda.

A API não mostra o motivo da falha do estorno. O pedido aparece só como FAILED.

Reaja ao estorno

Quando o gateway confirma o estorno, a venda muda de status e a PagPolar envia um evento. O que chega depende do caso:

SituaçãoEventoStatus da venda
Estorno da venda inteiraTRANSACTION_REFUNDEDREFUNDED
Estorno de um item, e ainda restam itens na vendaNenhumVolta para PAID
Estorno do último item da vendaTRANSACTION_REFUNDEDREFUNDED
Estorno de uma venda que ainda não contava como pagaTRANSACTION_CANCELEDCANCELED

"Contava como paga" quer dizer: a venda estava em PAID, REFUNDING, ASK_REFUND, ASK_PARTIAL_REFUND ou CHARGEBACK_APPROVED.

Exemplo resumido de TRANSACTION_REFUNDED:

{
  "event": "TRANSACTION_REFUNDED",
  "data": {
    "transaction": {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "identifier": "PPO9876543210",
      "status": "REFUNDED",
      "payment_method": "PIX",
      "total_amount": "197.0000",
      "refund_reason": "Produto não atendeu às expectativas"
    }
  }
}

Ao receber TRANSACTION_REFUNDED:

  1. Confira o data.transaction.status. Se já for REFUNDED no seu sistema, ignore.
  2. Revogue o acesso ao que foi vendido.
  3. Marque o pedido como reembolsado.

Ao receber TRANSACTION_CANCELED depois de um pedido de reembolso, cancele o pedido no seu sistema.

Para saber o valor devolvido no estorno de um item sem evento, consulte GET /refunds?status=REFUNDED e leia is_partial e refund_amount.

O estorno pode chegar sem pedido antes

TRANSACTION_REFUNDED também chega quando o estorno acontece sem pedido de reembolso aberto. Trate o evento mesmo sem ter recebido TRANSACTION_ASK_REFUNDING antes.

Reembolsar uma venda pela API

Use POST /refunds quando você decide devolver o dinheiro — por acordo com o cliente, por engano na cobrança ou por uma regra do seu sistema.

O estorno é imediato e não tem volta

O pedido criado por esta rota já nasce aceito: o estorno vai para o gateway na hora e os acessos do cliente são revogados. Não existe rota para desfazer.

O reembolso é sempre da venda inteira. Reembolsar só alguns itens continua no painel.

curl -X POST "https://api.pagpolar.com/v1/refunds" \
  -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>" \
  -H "Idempotency-Key: 2f1c4d2e-8f4a-4c1e-9f7b-6a2d1e3c5b90" \
  -H "Content-Type: application/json" \
  -d '{
    "sale_identifier": "PPO9876543210",
    "requested_by": "CLIENT",
    "reason": "Cliente desistiu da compra"
  }'
const apiUrl = 'https://api.pagpolar.com/v1';
const accessToken = '<SEU_TOKEN_DE_ACESSO>';

const response = await fetch(`${apiUrl}/refunds`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    sale_identifier: 'PPO9876543210',
    requested_by: 'CLIENT',
    reason: 'Cliente desistiu da compra',
  }),
});

if (!response.ok) {
  throw new Error(`Erro ${response.status}: ${await response.text()}`);
}

const { data } = await response.json();

console.log(data.id, data.status);
CampoObrigatórioO que é
sale_identifierSimCódigo público da venda — o identifier que vem em GET /sales, na resposta da cobrança e no payload dos webhooks. Vem com o prefixo, como PPO9876543210. O código sem o prefixo ou a URL do checkout com o código também servem. Não é o id (uuid) da venda: com o uuid a resposta é 404.
requested_byNãoQuem pediu o reembolso: SELLER (padrão) quando a decisão foi sua, CLIENT quando o comprador pediu por fora, por e-mail ou atendimento. Só muda o registro, que volta em requested_by na consulta — o estorno é imediato nos dois casos.
reasonNãoMotivo, em texto livre, que fica gravado no pedido.
customer_observationNãoObservação do comprador, quando houver.

A resposta é 201 com o pedido já criado:

{
  "data": {
    "id": "3f1c4d2e-8f4a-4c1e-9f7b-6a2d1e3c5b90",
    "status": "REFUNDING",
    "requested_by": "CLIENT",
    "is_partial": false,
    "refund_amount": null,
    "reason": "Cliente desistiu da compra",
    "sale": {
      "identifier": "PPO9876543210",
      "status": "REFUNDING",
      "payment_method": "PIX",
      "total_amount": 197
    }
  }
}
Situação na respostaO que aconteceuO que fazer
REFUNDINGO gateway aceitou o pedido de estorno e ainda não confirmou.Espere TRANSACTION_REFUNDED para revogar o acesso.
FAILEDO gateway recusou o estorno, por exemplo por falta de saldo de um co-produtor.Consulte GET /refunds e peça o reprocessamento pelo painel.

Quando a venda não pode ser reembolsada

SituaçãoRespostaComo resolver
Código de uma venda de outra conta, ou código inexistente.404 not_foundConfira o identifier da venda em GET /sales.
Venda que não está paga nem com pedido aberto (por exemplo, OPEN, REFUNDED ou CANCELED).409 conflictSó venda paga pode ser reembolsada. Veja Ciclo de vida da venda.
A venda já tem um pedido de reembolso em andamento.400 invalid_requestConsulte GET /refunds?sale_identifier=CODIGO_DA_VENDA e acompanhe o pedido existente.

Chargeback

Chargeback é a contestação da compra pelo banco do cliente. Não existe pedido nem decisão no painel: o gateway avisa a PagPolar quando o chargeback é aprovado.

O diagrama mostra o que acontece quando o aviso chega.

O que muda na PagPolar:

O quêEfeito
Status da vendaVira CHARGEBACK_APPROVED. Se a venda já estava REFUNDED ou CANCELED, o status não muda.
EventoTRANSACTION_CHARGEBACK_APPROVED é enviado nos dois casos acima.
Pedidos de reembolso da vendaOs que estavam PENDING, ACCEPTED ou ACCEPTED_BY_ADMIN viram CANCELED.
Assinatura da vendaA PagPolar pede o cancelamento, se a venda não estava REFUNDED nem CANCELED. Veja Cancelar assinatura.

Exemplo resumido:

{
  "event": "TRANSACTION_CHARGEBACK_APPROVED",
  "data": {
    "transaction": {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "identifier": "PPO9876543210",
      "status": "CHARGEBACK_APPROVED",
      "payment_method": "CREDIT_CARD",
      "total_amount": "197.0000",
      "chargeback_approved_at": "2026-09-15T12:00:00.000Z"
    }
  }
}

Ao receber TRANSACTION_CHARGEBACK_APPROVED:

  1. Revogue o acesso ao que foi vendido.
  2. Guarde data.transaction.chargeback_approved_at. A venda na API não traz essa data.
  3. Se a venda tinha um pedido de reembolso aberto no seu sistema, marque o pedido como cancelado.

Para listar as vendas com chargeback aprovado, filtre a listagem de vendas pelo status:

curl "https://api.pagpolar.com/v1/sales?status=CHARGEBACK_APPROVED&per_page=100" \
  -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>"
const apiUrl = 'https://api.pagpolar.com/v1';
const accessToken = '<SEU_TOKEN_DE_ACESSO>';

const query = new URLSearchParams({
  status: 'CHARGEBACK_APPROVED',
  per_page: '100',
});

const response = await fetch(`${apiUrl}/sales?${query}`, {
  headers: { Authorization: `Bearer ${accessToken}` },
});

if (!response.ok) {
  throw new Error(`Erro ${response.status}: ${await response.text()}`);
}

const body = await response.json();

console.log(body.data.map((sale) => sale.identifier));

Não há aviso antes da aprovação

A PagPolar só envia evento quando o chargeback é aprovado. Não existe evento para chargeback aberto ou em análise.

Situações do pedido de reembolso

O diagrama mostra os caminhos principais de um pedido de reembolso.

SituaçãoSignificadoO que fazer
PENDINGO pedido espera a resposta do vendedor.Aguarde.
ACCEPTEDO vendedor aceitou. O estorno vai ser pedido ao gateway.Aguarde o estorno.
ACCEPTED_BY_ADMINA PagPolar aceitou, inclusive por aprovação automática de pedido sem resposta.Aguarde o estorno.
REFUSEDO vendedor recusou. A venda volta para PAID, se estava em pedido de reembolso.Mantenha o acesso.
REFUSED_BY_ADMINA PagPolar recusou. A venda volta para PAID, se estava em pedido de reembolso.Mantenha o acesso.
WAITING_SEND, WAITING_TRACK_CODE, SENTEtapas da devolução de um produto físico. WAITING_TRACK_CODE aparece quando o vendedor exige a devolução do produto físico.Aguarde.
REFUNDINGO estorno foi pedido ao gateway e ainda não foi confirmado.Aguarde TRANSACTION_REFUNDED.
REFUNDEDO estorno foi concluído.Revogue o acesso, se ainda não fez.
CANCELEDO pedido foi desfeito, ou a venda teve chargeback aprovado.Mantenha o acesso se a venda voltou para PAID.
FAILEDO gateway recusou o estorno.Aguarde. O vendedor resolve pelo painel.

Eventos de webhook deste fluxo

Quando algo dá errado

Além dos erros comuns a todas as rotas, este fluxo pode responder:

PassoSituaçãoRespostaComo resolver
Consultar o pedidostatus com um valor fora da lista de situações.400 invalid_requestUse um valor da tabela Situações do pedido de reembolso.
Consultar o pedidocreated_from ou created_to fora do formato ISO 8601.400 invalid_requestEnvie data e hora completas: 2026-09-15T23:59:59-03:00.
Consultar o pedidosale_identifier com o id (uuid) da venda, ou com o código de uma venda de outra conta.200 com data vazioEnvie o código da venda (identifier), com ou sem o prefixo.
ChargebackTRANSACTION_CHARGEBACK_APPROVED chegou com status: "REFUNDED" ou "CANCELED".Status mantidoA venda já tinha sido estornada ou cancelada. Registre o chargeback sem mudar o status.

Próximos passos