Skip to main content
Disputa é a contestação de um PIX pelo pagador (MED, o Mecanismo Especial de Devolução). O comprador aciona o banco dele dizendo, por exemplo, que não recebeu o produto, e o valor daquela venda fica retido no seu saldo até o banco decidir. Enquanto a disputa está aberta ou depois que ela é perdida, o valor aparece em disputeBlocked na carteira e sai do withdrawable. Não dá pra sacar o que está contestado. Tudo o que o painel faz com disputa a API também faz: listar, consultar, responder com provas e receber o resultado por webhook. A chave precisa da permissão Gerenciar disputas (disputas.gerenciar).

O fluxo

1

Chega o webhook dispute.opened

A disputa acabou de abrir. O corpo traz o disputeId, o orderCode e o endToEndId da venda. Veja o corpo dos eventos.
2

Você junta as provas da venda

Comprovante de entrega, log de acesso, conversa com o comprador. Use o orderCode para achar a venda do seu lado.
3

Envia a defesa

POST /v1/disputes/{id}/evidence com os arquivos e a sua explicação. A defesa vai direto ao banco do pagador.
4

Acompanha o resultado

dispute.under_review quando o banco começa a analisar, e depois dispute.won (o valor volta ao saldo) ou dispute.lost (o valor volta ao pagador).

Status

Não precisa replicar essa regra do seu lado: o campo canRespond já diz se a disputa aceita resposta agora.
Disputa nasce de uma transação real, então não existe em sandbox. Com chave ps_test_, a lista volta vazia com "sandbox": true, a consulta responde 404 e o envio de provas responde 400.

Listando

Resposta 200
string
Um status ou vários separados por vírgula: aberta,pendente. Valor fora de aberta, pendente, resolvida e perdida responde 400.
string
Só as disputas desse pedido.
string
Só as disputas desse PIX.
string
Abertas a partir desta data (ISO 8601).
string
Abertas até esta data (ISO 8601).
integer
default:"50"
De 1 a 100. Use com offset para paginar.

Campos que valem atenção

boolean
true quando a disputa aceita resposta agora. Pode vir false numa disputa aberta nos primeiros minutos, enquanto o banco ainda não registrou a contestação.
string
Identificador da contestação no banco. Vem vazio logo depois da abertura.
object
A situação da sua defesa.
string
A subconta da venda contestada, quando houver. O valor fica retido nela.
Mesmo com o webhook, vale rodar a listagem com status=aberta uma vez por dia. Disputa tem prazo, e perder por não ter respondido é o pior jeito de perder.

Respondendo

Só disputa com canRespond: true aceita resposta. Você pode mandar arquivos, links e um texto explicando o caso, em qualquer combinação. Um dos três é obrigatório.
Resposta 200
array
Até 5 arquivos de até 5 MB cada, em PDF, PNG, JPEG ou WebP. Cada item é { "name", "data" }, com data em data URL base64. A gente guarda o arquivo e anexa à defesa.
array
Até 10 links públicos de provas, cada um como { "url", "description" }. Link sem http ou https é descartado.
string
A sua explicação do caso. Vira um PDF anexado à defesa.
integer
Quantas provas entraram neste envio: arquivos, links válidos e o PDF do texto.
boolean
true quando a defesa já foi entregue ao banco. false quando ficou registrada aqui e a nossa equipe encaminha.
Prefira files. Vários bancos recebem a defesa só como arquivo: o que vai em files segue anexado, e o que vai em documents aparece citado no texto. Se o seu comprovante está numa página, gere um PDF e mande como arquivo.
Para transformar um arquivo em data URL no Node:
O corpo inteiro da requisição pode ter até 25 MB. Enquanto a disputa aceitar resposta, você pode enviar de novo: cada envio soma provas, não substitui as anteriores.

Consultando uma disputa

Volta a mesma disputa da listagem, com as provas já enviadas e o campo history, a linha do tempo dos status. Cada item corresponde a um webhook enviado:
Os links das provas são assinados e expiram. Não guarde a URL: guarde o id e consulte de novo quando precisar. Disputa que não é da sua conta responde 404, e não 403. É proposital: a API não confirma a existência de recurso de terceiro.

Webhooks

Quatro eventos acompanham a disputa: dispute.opened, dispute.under_review, dispute.won e dispute.lost. Eles chegam nas mesmas URLs de webhook da conta, com o mesmo corpo, mudando só o event e o status. O corpo completo está em Como funcionam os webhooks. O X-Webhook-Id desses eventos é evento:disputeId, por exemplo dispute.opened:665f1c2ab9e8d40012a4c789. Cada mudança de status de cada disputa tem a sua chave, então duas disputas do mesmo pedido nunca se confundem na sua deduplicação.

O que costuma funcionar como prova

Prova de entrega

Log de acesso, e-mail de entrega com data e hora, código de rastreio, print do sistema mostrando a liberação.

Prova de aceite

Termos aceitos, confirmação de recebimento, conversa em que o comprador reconhece que recebeu.

Identidade do comprador

O endToEndId da transação, o e-mail usado na compra, o externalId que amarra ao usuário da sua base.

Contexto de uso

Histórico mostrando que a conta foi usada depois da compra. É o que mais derruba “produto não recebido”.
Junte as provas de forma programática assim que o pagamento confirma, não quando a disputa chega. Trinta dias depois o log já rotacionou e o print não existe mais.

Erros