Skip to content

Devolução PIX

Inicia uma devolução (total ou parcial) de uma transação PIX recebida.

Endpoint

POST /api/external/pix/refund

Headers

HeaderTipoObrigatórioDescrição
AuthorizationStringSimApiKey {client_id}:{client_secret}
Content-TypeStringSimapplication/json
hmacStringSimAssinatura HMAC-SHA512 do body (saiba mais)
Idempotency-KeyStringSimChave única do comando de devolução: 8 a 180 chars, charset A-Za-z0-9._:-. Sem ela (ou fora do formato) a API responde 400 idempotency_key_required. Reenviar a MESMA chave faz replay do mesmo comando durável.
X-Key-CaseStringNãoDefina como camelCase para receber os campos da resposta em camelCase (padrão é snake_case)

Request Body

CampoTipoObrigatórioDescriçãoExemplo
original_transaction_idStringSimReferência da transação PIX original: transactionId, E2E ou TXID da cobrança (veja abaixo)"E18236120202608210335s13ed93de5b"
amountIntegerNãoValor a devolver em centavos no request. Se omitido, devolve o valor total da transação original.3000 (R$ 30,00)
reasonStringNãoCódigo de devolução BACEN (veja tabela abaixo). Padrão: MD06. Validado localmente: código fora da lista aceita responde 422 síncrono."MD06"
descriptionStringNãoDescrição da devolução (até 140 caracteres na API; o texto enviado no campo ISO é limitado pelo leiaute). Padrão: "Devolução PIX"."Devolução solicitada pelo cliente"

Aliases aceitos

Para flexibilidade de integração, o backend aceita múltiplos nomes para cada campo (primeiro encontrado vence):

  • original_transaction_id (canônico)
    • valor aceito: transactionId do webhook, E2E (prefixo E) ou txId da cobrança QR
    • original_e2e_id - alias para o E2E ID da transação original
    • originalTransactionId - camelCase
    • transaction_id - fallback
    • end_to_end_id - fallback
  • reason (canônico)
    • return_code - alias direto

Validação de ownership

O backend valida se a transação original pertence ao mesmo merchant da API Key que está chamando o endpoint. Se você tentar devolver uma transação de outro merchant, recebe HTTP 404 "original transaction not found" - mesma resposta de transação inexistente (por segurança).

Valores monetários (request × response)

O amount do request é em centavos (R$ 1,00 = 100). O amount da response e dos webhooks é em subcentavos / unidades base (R$ 1,00 = 10000). Exemplo: envie 3000 para devolver R$ 30,00; a response retorna 300000.

NUNCA envie float/decimal. Sempre envie inteiro em centavos no request e divida valores de resposta por 10.000 para exibir em reais.

Devolução parcial -- como acompanhar o valor remanescente

Para devolução parcial, informe um amount menor que o valor original. O valor total das devoluções de uma mesma transação não pode exceder o valor original recebido.

O backend rastreia o acumulado em total_refunded e remaining_refundable nos webhooks pix.refund.completed e pix.return.received:

  • total_refunded = soma de todas as devoluções já executadas para aquele end_to_end_id original
  • remaining_refundable = amount_original - total_refunded (quanto ainda pode ser devolvido)
  • is_partial = true se essa devolução foi parcial

Antes de fazer uma segunda devolução parcial, consulte o último webhook pix.refund.completed para saber o remaining_refundable - se você exceder, o backend retorna HTTP 422 "Valor da devolução excede o valor original da transação".

Códigos de Devolução

CódigoDescrição
BE08Devolução MED por falha operacional do PSP pagador ou recebedor
FR01Devolução MED por fundada suspeita de fraude
MD06Devolução solicitada pelo usuário recebedor
SL02Devolução por erro ou desacordo em Pix Saque ou Pix Troco

Validação do reason code

O Monetarie valida o campo reason localmente contra a lista de códigos aceitos e encaminha o código ao BACEN via PACS.004.

  • Códigos válidos no ExternalReturnReason1Code da PACS.004: BE08, FR01, MD06, SL02.
  • Códigos de rejeição de outros leiautes, como AC03, AM09 e RR04, não são aceitos como motivo de uma nova PACS.004.

O controller também aceita return_code como alias de reason.

Um código fora da lista aceita (BE08, FR01, MD06, SL02) é recusado sincronamente com 422 e nenhum comando é criado.

Exemplo

bash
BODY='{"amount":3000,"description":"Devolução acordo","original_transaction_id":"E18236120202608210335s13ed93de5b","reason":"MD06"}'
HMAC=$(echo -n "$BODY" | openssl dgst -sha512 -hmac "$CLIENT_SECRET" | awk '{print $2}')

curl -X POST https://api.monetarie.com/api/external/pix/refund \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: refund-$(uuidgen)" \
  -H "hmac: $HMAC" \
  -d "$BODY"

Resposta de Sucesso -- 202

Uma requisição aceita responde 202: a devolução vira um comando durável e o resultado terminal chega pelos webhooks. Falhas de validação continuam respondendo com os códigos 4xx documentados abaixo.

json
{
  "worked": true,
  "transaction_id": "PIXRET8f4c1b2a9d0e7f3a1c5b",
  "end_to_end_id": null,
  "original_end_to_end_id": "E18236120202608210335s13ed93de5b",
  "amount": 300000,
  "status": "held",
  "detail": "Devolucao registrada para processamento duravel"
}

HTTP 202 - acompanhe o resultado via GET /pix/refund/:id (use o transaction_id retornado), via GET /transactions/:id, ou aguarde pix.refund.completed / pix.refund.failed. O webhook preserva transactionId e endToEndId da devolução e inclui refundTransactionId, refundEndToEndId, returnId, originalTransactionId, originalEndToEndId, externalId e originalExternalId, permitindo correlacionar a devolução com a cobrança original sem depender de busca por texto.

Consulta da devolução

http
GET /api/external/pix/refund/:id

Use o transaction_id com prefixo PIXRET retornado pelo POST. A consulta exige a permissão transfer:read, não usa Idempotency-Key nem HMAC, e aplica o mesmo escopo da conta vinculada à API Key. Uma devolução de outra conta e um identificador inexistente produzem o mesmo HTTP 404.

json
{
  "worked": true,
  "data": {
    "transaction_id": "PIXRET8f4c1b2a9d0e7f3a1c5b",
    "refund_transaction_id": "PIXRET8f4c1b2a9d0e7f3a1c5b",
    "refund_end_to_end_id": "D46026562202609030331refund0001",
    "return_id": "D46026562202609030331refund0001",
    "original_transaction_id": "PIXINoriginal",
    "original_end_to_end_id": "E18236120202608210335s13ed93de5b",
    "external_id": "refund-order-1",
    "original_external_id": "order-1",
    "amount": 300000,
    "status": "settled",
    "reason_code": "MD06",
    "reason_description": "Devolução solicitada pelo usuário recebedor",
    "requested_at": "2026-09-03T03:30:00.000000Z",
    "completed_at": "2026-09-03T03:30:02.000000Z",
    "original_payer": {
      "name": "Pagador",
      "document": "123***09"
    },
    "original_recipient": {
      "name": "Recebedor",
      "document": "123***09"
    }
  }
}

refund_end_to_end_id e return_id representam o mesmo RtrId de devolução, com prefixo D. Enquanto a cabine ainda não o tiver atribuído, ambos podem ser null. Documentos de pessoas naturais das partes originais são mascarados.

E2E ID com prefixo D

Diferente de uma transação PIX OUT comum (E2E prefixo E), uma devolução tem E2E com prefixo D (de "Devolução"). Esse prefixo identifica o tipo ISO 20022 pacs.004 no BACEN. O transaction_id interno também tem prefixo PIXRET para facilitar identificação.

CampoTipoDescrição
workedBooleantrue indica que a requisição foi aceita
transaction_idStringIdentificador da devolução (prefixo PIXRET). Use para consultar status.
end_to_end_idNullSempre null no POST: o E2E da devolução (prefixo D) é cunhado pela cabine PIX e chega nos webhooks terminais (refundEndToEndId).
original_end_to_end_idStringE2E da transação original devolvida
amountIntegerValor da devolução em subcentavos (÷ 10.000 para reais). 300000 = R$ 30,00
statusStringEstado da esteira durável no instante da resposta: requested, held ou dispatched
detailStringMensagem descritiva

Resposta de Erro (404)

json
{
  "worked": false,
  "errors": {
    "not_found": "Transação original não encontrada"
  }
}

Resposta de Erro (422) -- Saldo insuficiente

json
{
  "worked": false,
  "errors": {
    "unprocessable_entity": "insufficient balance"
  }
}

Ocorre quando o saldo seguro (min(TB, PG) - ver Saldo) é menor que o amount solicitado. Devolução exige que a conta origem tenha saldo ≥ valor a devolver.

Resposta de Erro (422) -- Valor excedido

json
{
  "worked": false,
  "errors": {
    "unprocessable_entity": "Valor da devolução excede o valor original da transação"
  }
}

Ocorre quando o total de devoluções (atual + anteriores) excederia o amount da transação original. Devoluções parciais são permitidas, mas a soma não pode ultrapassar o valor recebido.

Resposta de Erro (400) -- Idempotency-Key ausente ou inválida

json
{
  "worked": false,
  "errors": {
    "idempotency_key_required": "Idempotency-Key valido e obrigatorio"
  }
}

Resposta de Erro (409) -- Idempotency-Key divergente

json
{
  "worked": false,
  "errors": {
    "idempotency_key_mismatch": "Idempotency-Key diverge do comando persistido"
  }
}

Ocorre quando a mesma Idempotency-Key é reenviada com corpo diferente do comando já persistido.

Resposta de Erro (400) -- original_transaction_id ausente

json
{
  "worked": false,
  "errors": {
    "bad_request": "original_transaction_id is required"
  }
}

Resposta de Erro (401)

json
{
  "worked": false,
  "errors": {
    "unauthorized": "Missing API key credentials. Use Authorization: ApiKey <client_id>:<client_secret>"
  }
}

Prazo para devolução

A esteira da cabine revalida a janela antes de montar a PACS.004:

  • devoluções comuns: até 90 dias corridos da transação original;
  • Pix Saque (OTHR) e Pix Troco (GSCB): até 1 hora do instante da operação original.

Este endpoint externo não faz essa validação de prazo antes do aceite. Portanto, uma solicitação pode responder 202 e depois terminar em pix.refund.failed por expiração da janela, sem envio da PACS.004. Use o webhook terminal como autoridade do resultado.

PACS.004 x MED: devoluções iniciadas por infração BACEN

Se a devolução que você está iniciando é consequência de uma infração BACEN (notificação via pix.refund.requested), não chame este endpoint. A devolução MED é executada automaticamente pelo backend quando o analysis_result=AGREED é decidido (defesa não submetida no prazo OU acatamento manual via merchant portal). Chamar POST /pix/refund em paralelo pode gerar duplicidade.

Este endpoint é para devoluções voluntárias iniciadas por você (ex: devolver um PIX recebido a mais, cancelar uma venda, acerto comercial). Ver Infrações (fluxo completo) para distinguir os dois cenários.

MONETARIE SOCIEDADE DE CRÉDITO DIRETO S.A. - SCD · CNPJ 46.026.562/0001-05 · ISPB 46026562