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
- Um token de acesso. Veja Autenticação.
- Uma credencial com webhook. Veja Configurar o webhook.
- Os eventos
TRANSACTION_ASK_REFUNDING,TRANSACTION_REFUNDED,TRANSACTION_CANCELEDeTRANSACTION_CHARGEBACK_APPROVEDescolhidos no webhook da credencial. - Um servidor de webhook que autentica as requisições e descarta eventos repetidos.
O que fica na API e o que fica no painel
| O que acontece | Onde |
|---|---|
| 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.status | Tipo de pedido |
|---|---|
ASK_REFUND | Reembolso da venda inteira. |
ASK_PARTIAL_REFUND | Reembolso de parte dos itens da venda. |
Faça assim:
- Grave o pedido junto da venda, usando o
data.transaction.id. - Guarde o
data.transaction.identifier. É o código da venda, com o prefixo, comoPPO9876543210: o mesmo valor da API. Use esse valor no filtrosale_identifierdo próximo passo. - 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
}
}| Campo | O que significa |
|---|---|
id | Id do pedido de reembolso. |
status | Situação do pedido. Veja Situações do pedido de reembolso. |
requested_by | Quem abriu o pedido: CLIENT (o cliente) ou SELLER (o vendedor ou a PagPolar). |
is_partial | true quando o pedido é de parte dos itens. |
refund_amount | Valor do reembolso parcial, em reais, como número: 49.9 = R$ 49,90. null no reembolso da venda inteira. |
reason | Motivo informado no pedido. |
refused_reason | Motivo da recusa. null se não foi recusado. |
canceled_reason | Motivo do cancelamento. null se não foi cancelado. |
return_tracking | Rastreio da devolução de produto físico. null quando não há rastreio. |
sale | Resumo da venda: identifier, status, payment_method e total_amount. |
customer | O cliente, com documento e telefone mascarados. |
Filtros aceitos:
| Parâmetro | O que faz |
|---|---|
sale_identifier | Traz só os pedidos da venda com esse código. |
status | Traz só os pedidos nessa situação. |
created_from e created_to | Traz os pedidos criados nesse intervalo. Data e hora em ISO 8601 com fuso. |
page e per_page | Paginaçã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:

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:

| Decisão | Situação do pedido | Status da venda | Evento |
|---|---|---|---|
| Aceito pelo vendedor | ACCEPTED, depois REFUNDING | Venda inteira: REFUNDING. Parte dos itens: não muda. | Nenhum |
| Aceito pela PagPolar | ACCEPTED_BY_ADMIN, depois REFUNDING | Igual ao aceito pelo vendedor. | Nenhum |
| Recusado | REFUSED ou REFUSED_BY_ADMIN | Se estava em ASK_REFUND ou ASK_PARTIAL_REFUND, volta para PAID. Em outro status, não muda. | Nenhum |
| Cancelado | CANCELED | Volta para PAID. | Nenhum |
| O gateway recusou o estorno | FAILED | Venda 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ção | Evento | Status da venda |
|---|---|---|
| Estorno da venda inteira | TRANSACTION_REFUNDED | REFUNDED |
| Estorno de um item, e ainda restam itens na venda | Nenhum | Volta para PAID |
| Estorno do último item da venda | TRANSACTION_REFUNDED | REFUNDED |
| Estorno de uma venda que ainda não contava como paga | TRANSACTION_CANCELED | CANCELED |
"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:
- Confira o
data.transaction.status. Se já forREFUNDEDno seu sistema, ignore. - Revogue o acesso ao que foi vendido.
- 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);| Campo | Obrigatório | O que é |
|---|---|---|
sale_identifier | Sim | Có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_by | Não | Quem 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. |
reason | Não | Motivo, em texto livre, que fica gravado no pedido. |
customer_observation | Não | Observaçã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 resposta | O que aconteceu | O que fazer |
|---|---|---|
REFUNDING | O gateway aceitou o pedido de estorno e ainda não confirmou. | Espere TRANSACTION_REFUNDED para revogar o acesso. |
FAILED | O 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ção | Resposta | Como resolver |
|---|---|---|
| Código de uma venda de outra conta, ou código inexistente. | 404 not_found | Confira o identifier da venda em GET /sales. |
Venda que não está paga nem com pedido aberto (por exemplo, OPEN, REFUNDED ou CANCELED). | 409 conflict | Só venda paga pode ser reembolsada. Veja Ciclo de vida da venda. |
| A venda já tem um pedido de reembolso em andamento. | 400 invalid_request | Consulte 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 venda | Vira CHARGEBACK_APPROVED. Se a venda já estava REFUNDED ou CANCELED, o status não muda. |
| Evento | TRANSACTION_CHARGEBACK_APPROVED é enviado nos dois casos acima. |
| Pedidos de reembolso da venda | Os que estavam PENDING, ACCEPTED ou ACCEPTED_BY_ADMIN viram CANCELED. |
| Assinatura da venda | A 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:
- Revogue o acesso ao que foi vendido.
- Guarde
data.transaction.chargeback_approved_at. A venda na API não traz essa data. - 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ção | Significado | O que fazer |
|---|---|---|
PENDING | O pedido espera a resposta do vendedor. | Aguarde. |
ACCEPTED | O vendedor aceitou. O estorno vai ser pedido ao gateway. | Aguarde o estorno. |
ACCEPTED_BY_ADMIN | A PagPolar aceitou, inclusive por aprovação automática de pedido sem resposta. | Aguarde o estorno. |
REFUSED | O vendedor recusou. A venda volta para PAID, se estava em pedido de reembolso. | Mantenha o acesso. |
REFUSED_BY_ADMIN | A PagPolar recusou. A venda volta para PAID, se estava em pedido de reembolso. | Mantenha o acesso. |
WAITING_SEND, WAITING_TRACK_CODE, SENT | Etapas da devolução de um produto físico. WAITING_TRACK_CODE aparece quando o vendedor exige a devolução do produto físico. | Aguarde. |
REFUNDING | O estorno foi pedido ao gateway e ainda não foi confirmado. | Aguarde TRANSACTION_REFUNDED. |
REFUNDED | O estorno foi concluído. | Revogue o acesso, se ainda não fez. |
CANCELED | O pedido foi desfeito, ou a venda teve chargeback aprovado. | Mantenha o acesso se a venda voltou para PAID. |
FAILED | O gateway recusou o estorno. | Aguarde. O vendedor resolve pelo painel. |
Eventos de webhook deste fluxo
TRANSACTION_ASK_REFUNDING: veja Receba o pedido de reembolso.TRANSACTION_REFUNDEDeTRANSACTION_CANCELED: veja Reaja ao estorno.TRANSACTION_CHARGEBACK_APPROVED: veja Chargeback.
Quando algo dá errado
Além dos erros comuns a todas as rotas, este fluxo pode responder:
| Passo | Situação | Resposta | Como resolver |
|---|---|---|---|
| Consultar o pedido | status com um valor fora da lista de situações. | 400 invalid_request | Use um valor da tabela Situações do pedido de reembolso. |
| Consultar o pedido | created_from ou created_to fora do formato ISO 8601. | 400 invalid_request | Envie data e hora completas: 2026-09-15T23:59:59-03:00. |
| Consultar o pedido | sale_identifier com o id (uuid) da venda, ou com o código de uma venda de outra conta. | 200 com data vazio | Envie o código da venda (identifier), com ou sem o prefixo. |
| Chargeback | TRANSACTION_CHARGEBACK_APPROVED chegou com status: "REFUNDED" ou "CANCELED". | Status mantido | A venda já tinha sido estornada ou cancelada. Registre o chargeback sem mudar o status. |