> ## Documentation Index
> Fetch the complete documentation index at: https://paysure.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Devolver PIX (estorno)

> Devolve **integralmente** um cash-in recebido de volta para o pagador original.

**Regras:**
- Só devolução **total** (o valor bruto original).
- **Nada é revertido**: nem a taxa, nem eventuais splits/direct splits (permanecem nas
  wallets de destino). Sua conta é debitada o **valor bruto integral** — você precisa ter
  esse valor de saldo disponível (senão `422`).
- Apenas cash-ins **pagos** de até **3 dias**.
- Informe `external_id` **ou** `e2e` do cash-in a devolver.
- Recurso liberado por conta — fale com o suporte para habilitar.

A resposta é **`202` com `status: processing`**: a liquidação é **assíncrona**. Quando a
devolução liquidar (ou falhar), enviamos um **webhook** para o `postbackUrl` do cash-in
original com o resultado (`refunded` ou `failed`) — veja o schema `RefundWebhook`. Em caso
de `failed`, o valor debitado é **devolvido automaticamente** à sua wallet.


Devolve **integralmente** um cash-in recebido de volta para o pagador original.

## Fluxo

<Steps>
  <Step title="Você faz POST /v1/pix/refund">
    Envie `external_id` **ou** `e2e` do cash-in que quer devolver.
  </Step>

  <Step title="Recebe HTTP 202 com status processing">
    A devolução foi aceita e está liquidando (assíncrono, via SPI). O valor bruto é debitado da sua wallet.
  </Step>

  <Step title="Paysure envia webhook com o resultado">
    Você recebe um POST no `postbackUrl` do cash-in original com `refund.status`:

    * `refunded` → devolução **liquidada**.
    * `failed` → **rejeitada** pelo SPI; o valor debitado é **devolvido à sua wallet automaticamente**.
  </Step>
</Steps>

## Regras

* Só devolução **total** (o valor bruto original).
* **Nada é revertido**: nem a taxa, nem eventuais splits/direct splits (permanecem nas wallets de destino). Sua conta é debitada o **valor bruto integral** — você absorve a taxa e os splits.
* Você precisa ter o **valor bruto de saldo disponível** (senão `422` saldo insuficiente).
* Apenas cash-ins **pagos** de até **3 dias**.
* Informe `external_id` **ou** `e2e`.
* Recurso liberado por conta — fale com o suporte para habilitar.

<Warning>
  O valor debitado é o **bruto** (o que o pagador enviou), não o líquido que você recebeu.
  Se o cash-in teve taxa/splits, você devolve mais do que recebeu na wallet — o bruto cobre tudo.
</Warning>

<Note>
  A confirmação é **assíncrona** e chega por webhook. Não trate o `202 processing` como concluído —
  aguarde o webhook com `refund.status: "refunded"`.
</Note>

## Erros

Erros seguem o formato padrão `{ "message": "...", "ms": 123 }`. Nos erros específicos de
devolução vem também um campo **`code`** pra você diferenciar o motivo:

| HTTP | `code`            | Significado                                                     |
| ---- | ----------------- | --------------------------------------------------------------- |
| 403  | —                 | Recurso de devolução não habilitado para a conta.               |
| 404  | —                 | Cash-in não encontrado para esta conta.                         |
| 422  | `RF_INSUFFICIENT` | Saldo insuficiente para devolver o valor bruto.                 |
| 422  | `RF_ONLYU`        | A adquirente recusou a devolução (ex: fora do prazo BACEN).     |
| 422  | —                 | Cash-in não está pago / não é OnlyU / fora da janela de 3 dias. |
| 409  | `RF_LOCK`         | Uma devolução deste cash-in já está em processamento.           |

## Webhook de devolução

Payload enviado ao seu `postbackUrl` quando a devolução finaliza (uma vez por transição):

```json theme={null}
{
  "refund": {
    "reference_code": "PSR-3d47dc3f-4c5a-43c6-a057-c9db8816d9a6",
    "external_reference": "order-12345",
    "status": "refunded",
    "amount_cents": 10000,
    "end_to_end": "E10573521202607100056fw0B5CHeixU",
    "devolucao_e2e": "D29477089202607100059131981f0d63"
  }
}
```


## OpenAPI

````yaml POST /v1/pix/refund
openapi: 3.0.3
info:
  title: Paysure API
  version: 1.0.0
  description: |
    API REST da Paysure para integração de pagamentos PIX em produção.

    **Capacidades:**
    - Geração de cobranças PIX (cash-in) com QR Code dinâmico
    - Pagamento de chaves PIX e QR Codes (cash-out)
    - Splits configuráveis por transação (até 20 destinatários, % do bruto)
    - Webhooks idempotentes para confirmação de pagamento
    - Consulta de status de transações
    - Chave PIX estática personalizada com identificador embutido

    Todas as transações são em **centavos** (`value_cents`) e em moeda **BRL**.
  contact:
    name: Paysure Suporte
    url: https://paysure.com.br/
servers:
  - url: https://api.paysurebr.com
    description: Produção
security:
  - ClientCredentials: []
paths:
  /v1/pix/refund:
    post:
      tags:
        - Refund
      summary: Devolver uma cobrança PIX recebida (estorno ao pagador)
      description: >
        Devolve **integralmente** um cash-in recebido de volta para o pagador
        original.


        **Regras:**

        - Só devolução **total** (o valor bruto original).

        - **Nada é revertido**: nem a taxa, nem eventuais splits/direct splits
        (permanecem nas
          wallets de destino). Sua conta é debitada o **valor bruto integral** — você precisa ter
          esse valor de saldo disponível (senão `422`).
        - Apenas cash-ins **pagos** de até **3 dias**.

        - Informe `external_id` **ou** `e2e` do cash-in a devolver.

        - Recurso liberado por conta — fale com o suporte para habilitar.


        A resposta é **`202` com `status: processing`**: a liquidação é
        **assíncrona**. Quando a

        devolução liquidar (ou falhar), enviamos um **webhook** para o
        `postbackUrl` do cash-in

        original com o resultado (`refunded` ou `failed`) — veja o schema
        `RefundWebhook`. Em caso

        de `failed`, o valor debitado é **devolvido automaticamente** à sua
        wallet.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefundRequest'
            example:
              external_id: order-12345
              description: Reembolso pedido cancelado
      responses:
        '200':
          description: >-
            Devolução já solicitada anteriormente (idempotente) — retorna a
            existente.
        '202':
          description: Devolução aceita e em processamento
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefundResponse'
              example:
                ok: true
                refund:
                  refund_id: RF1179257B2CE641768AB17C
                  status: processing
                  amount_cents: 10000
                  reference_code: PSR-3d47dc3f-4c5a-43c6-a057-c9db8816d9a6
                  external_id: order-12345
                note: >-
                  Devolução aceita e em processamento. A confirmação será
                  enviada por webhook.
        '403':
          description: Recurso de devolução não habilitado para esta conta.
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
components:
  schemas:
    RefundRequest:
      type: object
      description: >-
        Informe `external_id` **ou** `e2e` do cash-in a devolver (pelo menos
        um).
      properties:
        external_id:
          type: string
          maxLength: 191
          nullable: true
          description: >-
            external_id do cash-in original (o mesmo que você enviou ao gerar a
            cobrança).
        e2e:
          type: string
          maxLength: 191
          nullable: true
          description: End-to-end (E2E) do cash-in original. Alternativa ao external_id.
        description:
          type: string
          maxLength: 140
          nullable: true
          description: Descrição da devolução (aparece no comprovante). Máx 140 caracteres.
    RefundResponse:
      type: object
      properties:
        ok:
          type: boolean
        refund:
          type: object
          properties:
            refund_id:
              type: string
              description: Identificador único da devolução.
            status:
              type: string
              enum:
                - processing
                - paid
              description: >-
                `processing` = aceito, aguardando liquidação assíncrona
                (confirmação via webhook).
            amount_cents:
              type: integer
              description: Valor bruto devolvido, em centavos.
            reference_code:
              type: string
              description: reference_code do cash-in original.
            external_id:
              type: string
    Error:
      type: object
      properties:
        message:
          type: string
        ms:
          type: number
          description: Tempo de processamento da request em ms.
  responses:
    NotFound:
      description: Recurso não encontrado.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ValidationError:
      description: Erro de validação (campos faltando ou inválidos).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ClientCredentials:
      type: apiKey
      in: header
      name: ci
      description: >
        Autenticação por par client-credentials. Envie **dois headers** em toda
        requisição:


        - `ci`: client_id (público)

        - `cs`: client_secret (privado — nunca exponha no frontend)


        Gere as credenciais no painel da Paysure em **API Keys**. Você pode ter
        múltiplas chaves ativas.

````