# Introdução

Leitura rápida para entender como a Pagou pode ajudar o seu negócio.

Bem-vindo à documentação da API do Pagou! Nossa API permite que você integre pagamentos rápidos e seguros em sua loja virtual, site ou aplicativo, utilizando métodos como **Pix** e **Boleto**.\
Desenvolvida com padrões modernos, a API do Pagou é fácil de usar, seja você um desenvolvedor iniciante ou experiente.

### O que é a API do Pagou?

A API do Pagou é uma ferramenta que conecta sua plataforma aos nossos serviços de pagamento. Com ela, você pode:

* **Processar pagamentos via Pix e Boleto** em menos de 1 minuto.
* **Integrar com plataformas de e-commerce** como WooCommerce, PerfexCRM, WHMCS, entre outras.
* **Acompanhar transações** em tempo real.
* **Configurar regras de negócio** para receber pagamentos de forma automática.

Nossa API segue padrões REST, com requisições em JSON e respostas claras, facilitando a integração em qualquer linguagem de programação.

### Para quem é esta documentação?

* **Desenvolvedores** que querem adicionar pagamentos ao seu site ou app.
* **Empresas de e-commerce** que usam plataformas como WooCommerce, PerfexCRM ou WHMCS.
* **Empreendedores** que buscam uma solução de pagamento simples e com baixas taxas.

...


# Credenciais de acesso

Veja como facilmente obter as suas credenciais de acesso

Para consumir a API, é necessário autenticar-se utilizando uma chave de acesso única (`API Key`). Essa chave deve ser enviada no cabeçalho de todas as requisições.

#### Obtendo sua API Key

Sua `API Key` está disponível dentro da conta do usuário. Para acessá-la:

1. Faça login no sistema.
2. Acesse o link: [Configurações da API](https://app.pagou.com.br/configuracoes/api).
3. Copie a chave de acesso exibida.

#### Enviando Credenciais

A autenticação é realizada enviando a `API Key` no cabeçalho **X-API-KEY** de todas as requisições.

**Exemplo de cabeçalho HTTP:**

`X-API-KEY: 123e4567-e89b-12d3-a456-426614174000`

Exemplo de Requisição

**Requisição com cURL:**

```bash
curl -X GET https://api.pagou.com.br/v1/pix \
-H "X-API-KEY: 123e4567-e89b-12d3-a456-426614174000"
```

#### Renovação de Credenciais

Caso sua chave de acesso expire ou seja comprometida, você pode gerar uma nova diretamente no link: [Configurações da API](https://app.pagou.com.br/configuracoes/api).

#### Boas Práticas

* **Proteja sua API Key**: Nunca compartilhe publicamente.
* **Rotacione periodicamente**: Troque sua chave de acesso regularmente para reforçar a segurança.
* **Revogue chaves comprometidas**: Caso suspeite de uso indevido, gere uma nova chave imediatamente no link acima.


# Integração com a API

#### Introdução

A integração com a API foi projetada para ser simples e eficiente. Os endpoints seguem o padrão RESTful, e os dados são enviados e recebidos no formato **JSON**.

#### URL Base

A API oferece dois ambientes distintos: **Produção** e **Sandbox** (para testes). Certifique-se de utilizar a URL apropriada para o seu caso.

| Ambiente | URL Base                           | Descrição                                            |
| -------- | ---------------------------------- | ---------------------------------------------------- |
| Produção | `https://api.pagou.com.br`         | Ambiente real, utilizado para operações em produção. |
| Sandbox  | `https://sandbox-api.pagou.com.br` | Ambiente de testes, sem impacto em dados reais.      |

#### Headers Necessários

Todas as requisições à API exigem os seguintes cabeçalhos:

| Cabeçalho      | Obrigatório | Descrição                                                                                                    |
| -------------- | ----------- | ------------------------------------------------------------------------------------------------------------ |
| `X-API-KEY`    | Sim         | Sua chave de autenticação. Disponível em [Configurações da API](https://app.pagou.com.br/configuracoes/api). |
| `Content-Type` | Sim         | Indica o formato do corpo da requisição. Use sempre `application/json`.                                      |
| `User-Agent`   | Sim         | Identifica o cliente ou aplicação que está fazendo a requisição.                                             |

**Dica de segurança**: Nunca exponha sua chave de API em código público (ex.: GitHub). Armazene-a em variáveis de ambiente ou arquivos de configuração seguros.

### Testando no Sandbox

O ambiente de sandbox permite simular pagamentos sem custos reais:

* Envie requisições para `https://sandbox-api.pagou.com.br`.
* Teste cenários como pagamento aprovado, recusado ou pendente.

**Dica**: Use ferramentas como Postman para testar requisições interativamente.

#### Explicação dos Headers Necessários

1. **`X-API-KEY`**: Este cabeçalho é fundamental para autenticação, assegurando que apenas usuários autorizados possam acessar a API. Sua chave pessoal pode ser encontrada nas configurações da API.
2. **`Content-Type`**: Este cabeçalho especifica o formato dos dados enviados no corpo da requisição. Para garantir que a API entenda corretamente as requisições, utilize sempre o valor `application/json`.
3. **`User-Agent`**: Este cabeçalho indica qual cliente ou aplicação está realizando a requisição. Isso pode ajudar no registro de logs e na análise de uso dos serviços da API.


# Meio de Pagamento: Boleto

{% openapi src="/files/qQQORCO54DSB83xSwPu7" path="/v1/charges" method="post" %}
[swagger.json](https://1531984135-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1aYQxJJrEOqi1xBa0bJL%2Fuploads%2FKax3MohVnD2iVqojDnGG%2Fswagger.json?alt=media\&token=27fd5a17-b704-47d7-8148-043f6b585530)
{% endopenapi %}

{% openapi src="/files/qQQORCO54DSB83xSwPu7" path="/v1/charges/{chargeID}" method="get" %}
[swagger.json](https://1531984135-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1aYQxJJrEOqi1xBa0bJL%2Fuploads%2FKax3MohVnD2iVqojDnGG%2Fswagger.json?alt=media\&token=27fd5a17-b704-47d7-8148-043f6b585530)
{% endopenapi %}

{% openapi src="/files/qQQORCO54DSB83xSwPu7" path="/v1/charges/{chargeID}" method="delete" %}
[swagger.json](https://1531984135-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1aYQxJJrEOqi1xBa0bJL%2Fuploads%2FKax3MohVnD2iVqojDnGG%2Fswagger.json?alt=media\&token=27fd5a17-b704-47d7-8148-043f6b585530)
{% endopenapi %}


# Criando um Boleto

A criação de boletos na API do Pagou permite gerar boletos para pagamento, com detalhes do cliente, cedente, e URLs para visualização em PDF ou HTML. Esta seção detalha o endpoint <mark style="color:green;">`POST`</mark>` ``/v1/charges`, o payload, a geração de URLs para visualização, autenticação, validação, exemplos de código, tratamento de erros, e boas práticas para criar boletos de forma robusta e segura.

### Visão Geral Técnica

O endpoint <mark style="color:green;">`POST`</mark>` ``/v1/charges` cria um boleto, retornando um ID único e informações básicas na resposta síncrona. Detalhes como código de barras, linha digitável, e informações bancárias são enviados posteriormente pelo webhook <mark style="color:orange;">`charge.created`</mark> (veja [Webhooks para Interações com Boletos](/integracao-com-a-api/meio-de-pagamento-pix/webhooks)) após o registro do boleto. Após a criação, o boleto pode ser visualizado em PDF (`https://fatura.pagou.com.br/boleto/pdf/{id}`) ou HTML (`https://fatura.pagou.com.br/boleto/{id}`), mas essas URLs podem não estar disponíveis imediatamente até o registro ser concluído.

**Especificações**:

* **Método**: `POST`
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/charges`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/charges`
* **Autenticação**: Cabeçalho `X-API-KEY` com chave do painel.
* **Content-Type**: `application/json`
* **Resposta**: `Status 201` Created com corpo JSON contendo o ID do boleto e detalhes.
* **Erros**: `400 Bad Request`, `401 Unauthorized`, `500 Internal Server Error`.

**Headers**

| Cabeçalho    | Valor                    | Descrição                                |
| ------------ | ------------------------ | ---------------------------------------- |
| Content-Type | `application/json`       | Formato JSON para o corpo da requisição. |
| X-API-KEY    | `<token>`                | Chave de autenticação do painel.         |
| User-Agent   | `NomeDaSuaAplicacao/1.0` | Identificador da aplicação.              |

### Corpo da Requisição

O payload deve conter informações do boleto, cliente, multas, juros, descontos e configurações de notificação.

```json
{
  "due_date": "2024-12-31",
  "grace_period": 15,
  "amount": 100.50,
  "description": "Payment for services rendered",
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    },
    {
      "key": "reference",
      "value": "REF-12345"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901",
    "zip": "01234567",
    "street": "Rua das Flores",
    "city": "São Paulo",
    "state": "SP",
    "number": "123",
    "neighborhood": "Centro"
  },
  "fine": 2.5,
  "interest": 1.0,
  "discount": {
    "type": "fixed",
    "amount": 10.00,
    "limit_date": "2024-12-25"
  },
  "notification_url": "https://your-webhook.com/notifications",
  "customer_code": "CUST-001"
}
```

**Campos do Payload**:

| **Campo**             | **Tipo** | **Obrigatório** | **Descrição**                                                            |
| --------------------- | -------- | --------------- | ------------------------------------------------------------------------ |
| `due_date`            | string   | Sim             | Data de vencimento (formato YYYY-MM-DD).                                 |
| `grace_period`        | number   | Sim             | Dias de tolerância após o vencimento (ex.: 15 dias).                     |
| `amount`              | number   | Sim             | Valor do boleto em reais (ex.: 100.50 para R$ 100,50).                   |
| `description`         | string   | Sim             | Descrição do boleto (máx. 255 caracteres).                               |
| `metadata`            | array    | Não             | Pares chave-valor para dados adicionais (ex.: ID do pedido).             |
| `metadata[].key`      | string   | Sim (se usado)  | Chave do metadado (ex.: order\_id).                                      |
| `metadata[].value`    | string   | Sim (se usado)  | Valor do metadado (ex.: ORD-2024-001).                                   |
| `payer`               | object   | Sim             | Dados do pagador.                                                        |
| `payer.name`          | string   | Sim             | Nome completo do pagador (máx. 100 caracteres).                          |
| `payer.document`      | string   | Sim             | CPF (11 dígitos) ou CNPJ (14 dígitos).                                   |
| `payer.zip`           | string   | Sim             | CEP (8 dígitos, sem hífen).                                              |
| `payer.street`        | string   | Sim             | Rua ou avenida (máx. 200 caracteres).                                    |
| `payer.city`          | string   | Sim             | Cidade (máx. 100 caracteres).                                            |
| `payer.state`         | string   | Sim             | UF (2 letras, ex.: SP).                                                  |
| `payer.number`        | string   | Sim             | Número do endereço (máx. 20 caracteres).                                 |
| `payer.neighborhood`  | string   | Sim             | Bairro (máx. 100 caracteres).                                            |
| `fine`                | number   | Não             | Multa por atraso em percentual (ex.: 2.5 para 2,5%).                     |
| `interest`            | number   | Não             | Juros por dia de atraso em percentual (ex.: 1.0 para 1%).                |
| `discount`            | object   | Não             | Desconto para pagamento antecipado.                                      |
| `discount.type`       | string   | Sim (se usado)  | Tipo de desconto (fixed ou percentage).                                  |
| `discount.amount`     | number   | Sim (se usado)  | Valor do desconto (em reais para fixed, ou percentual para percentage).  |
| `discount.limit_date` | string   | Sim (se usado)  | Data limite para o desconto (formato YYYY-MM-DD).                        |
| `notification_url`    | string   | Não             | URL HTTPS para webhooks (ex.: <https://your-webhook.com/notifications>). |
| `customer_code`       | string   | Não             | Código interno do cliente (máx. 50 caracteres).                          |

**Validações**:

* `due_date`: Deve ser uma data futura (mín. 1 dia).
* `grace_period`: Deve ser maior do que 0 e menor igual a 30.
* `amount`: Valor mínimo de 5.00 (R$ 5,00).
* `payer`.document: Deve ser um CPF (11 dígitos) ou CNPJ (14 dígitos) válido.
* `payer.zip`: Deve ser um CEP válido (8 dígitos).
* `discount.limit_date`: Deve ser anterior ou igual a due\_date.
* `notification_url`: Deve ser uma URL HTTPS válida.

### Resposta

* **Status**: 201 Created
* **Header**: Location: /charges/{id}
* **Corpo**: Contendo o ID do Boleto criado mais os dados.

**Response**

{% tabs %}
{% tab title="201" %}

```json
{
  "id": "d1bfda17-3a56-433b-8825-7981f7374cee",
  "due_date": "2024-12-31",
  "grace_period": 15,
  "amount": 100.50,
  "description": "Payment for services rendered",
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    },
    {
      "key": "reference",
      "value": "REF-12345"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901",
    "zip": "01234567",
    "street": "Rua das Flores",
    "city": "São Paulo",
    "state": "SP",
    "number": "123",
    "neighborhood": "Centro"
  },
  "fine": 2.5,
  "interest": 1.0,
  "discount": {
    "type": "fixed",
    "amount": 10.00,
    "limit_date": "2024-12-25"
  },
  "notification_url": "https://your-webhook.com/notifications",
  "customer_code": "CUST-001"

}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "error": "Invalid request"
}
```

{% endtab %}
{% endtabs %}

### Visualização do Boleto

Após a criação, o boleto pode ser visualizado em dois formatos:

* **PDF**: Acesse `https://fatura.pagou.com.br/boleto/pdf/{id}` (ex.: <https://fatura.pagou.com.br/boleto/pdf/1b6f2a39-2403-4217-a2ce-7d20e6376cf5>).
* **HTML**: Acesse `https://fatura.pagou.com.br/boleto/{id}` (ex.: <https://fatura.pagou.com.br/boleto/1b6f2a39-2403-4217-a2ce-7d20e6376cf5>).

**Nota**: Substitua {id} pelo UUID retornado (id). As URLs podem não estar disponíveis imediatamente, pois dependem do registro do boleto. Aguarde o webhook `charge.created` para confirmar a disponibilidade do boleto.

### Exemplos de Código

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://sandbox-api.pagou.com.br/v1/charges \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0" \
  -d '{
    "due_date": "2024-12-31",
    "grace_period": 15,
    "amount": 100.50,
    "description": "Payment for services rendered",
    "metadata": [
      {
        "key": "order_id",
        "value": "ORD-2024-001"
      },
      {
        "key": "reference",
        "value": "REF-12345"
      }
    ],
    "payer": {
      "name": "João Silva",
      "document": "12345678901",
      "zip": "01234567",
      "street": "Rua das Flores",
      "city": "São Paulo",
      "state": "SP",
      "number": "123",
      "neighborhood": "Centro"
    },
    "fine": 2.5,
    "interest": 1.0,
    "discount": {
      "type": "fixed",
      "amount": 10.00,
      "limit_date": "2024-12-25"
    },
    "notification_url": "https://your-webhook.com/notifications",
    "customer_code": "CUST-001"
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');
const { validate } = require('jsonschema');

// Esquema de validação do payload
const schema = {
    type: 'object',
    required: ['due_date', 'amount', 'description', 'payer'],
    properties: {
        due_date: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
        grace_period: { type: 'integer', minimum: 0 },
        amount: { type: 'number', minimum: 1.00 },
        description: { type: 'string', maxLength: 255 },
        metadata: {
            type: 'array',
            items: {
                type: 'object',
                required: ['key', 'value'],
                properties: {
                    key: { type: 'string' },
                    value: { type: 'string' }
                }
            }
        },
        payer: {
            type: 'object',
            required: ['name', 'document', 'zip', 'street', 'city', 'state', 'number', 'neighborhood'],
            properties: {
                name: { type: 'string', maxLength: 100 },
                document: { type: 'string', pattern: '^\\d{11}|\\d{14}$' },
                zip: { type: 'string', pattern: '^\\d{8}$' },
                street: { type: 'string', maxLength: 200 },
                city: { type: 'string', maxLength: 100 },
                state: { type: 'string', pattern: '^[A-Z]{2}$' },
                number: { type: 'string', maxLength: 20 },
                neighborhood: { type: 'string', maxLength: 100 }
            }
        },
        fine: { type: 'number', minimum: 0, maximum: 100 },
        interest: { type: 'number', minimum: 0, maximum: 100 },
        discount: {
            type: 'object',
            required: ['type', 'amount', 'limit_date'],
            properties: {
                type: { type: 'string', enum: ['fixed', 'percentage'] },
                amount: { type: 'number', minimum: 0 },
                limit_date: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' }
            }
        },
        notification_url: { type: 'string', format: 'uri' },
        customer_code: { type: 'string', maxLength: 50 }
    }
};

// Payload
const payload = {
    due_date: '2024-12-31',
    grace_period: 15,
    amount: 100.50,
    description: 'Payment for services rendered',
    metadata: [
        { key: 'order_id', value: 'ORD-2024-001' },
        { key: 'reference', value: 'REF-12345' }
    ],
    payer: {
        name: 'João Silva',
        document: '12345678901',
        zip: '01234567',
        street: 'Rua das Flores',
        city: 'São Paulo',
        state: 'SP',
        number: '123',
        neighborhood: 'Centro'
    },
    fine: 2.5,
    interest: 1.0,
    discount: {
        type: 'fixed',
        amount: 10.00,
        limit_date: '2024-12-25'
    },
    notification_url: 'https://your-webhook.com/notifications',
    customer_code: 'CUST-001'
};

// Validar payload
const validation = validate(payload, schema);
if (!validation.valid) {
    console.error('Erro de validação:', validation.errors);
    process.exit(1);
}

// Enviar requisição
fetch('https://sandbox-api.pagou.com.br/v1/charges', {
    method: 'POST',
    headers: {
        'X-API-KEY': 'sua_chave_api',
        'Content-Type': 'application/json',
        'User-Agent': 'MinhaLoja/1.0'
    },
    body: JSON.stringify(payload)
})
    .then(response => {
        if (!response.ok) {
            throw new Error(`Erro ${response.status}: ${response.statusText}`);
        }
        console.log(`Status: ${response.status}`);
        console.log(`Location: ${response.headers.get('Location')}`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
from jsonschema import validate, ValidationError

# Esquema de validação do payload
schema = {
    "type": "object",
    "required": ["due_date", "amount", "description", "payer"],
    "properties": {
        "due_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
        "grace_period": {"type": "integer", "minimum": 0},
        "amount": {"type": "number", "minimum": 1.00},
        "description": {"type": "string", "maxLength": 255},
        "metadata": {
            "type": "array",
            "items": {
                "type": "object",
                "required": ["key", "value"],
                "properties": {
                    "key": {"type": "string"},
                    "value": {"type": "string"}
                }
            }
        },
        "payer": {
            "type": "object",
            "required": ["name", "document", "zip", "street", "city", "state", "number", "neighborhood"],
            "properties": {
                "name": {"type": "string", "maxLength": 100},
                "document": {"type": "string", "pattern": "^\\d{11}|\\d{14}$"},
                "zip": {"type": "string", "pattern": "^\\d{8}$"},
                "street": {"type": "string", "maxLength": 200},
                "city": {"type": "string", "maxLength": 100},
                "state": {"type": "string", "pattern": "^[A-Z]{2}$"},
                "number": {"type": "string", "maxLength": 20},
                "neighborhood": {"type": "string", "maxLength": 100}
            }
        },
        "fine": {"type": "number", "minimum": 0, "maximum": 100},
        "interest": {"type": "number", "minimum": 0, "maximum": 100},
        "discount": {
            "type": "object",
            "required": ["type", "amount", "limit_date"],
            "properties": {
                "type": {"type": "string", "enum": ["fixed", "percentage"]},
                "amount": {"type": "number", "minimum": 0},
                "limit_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"}
            }
        },
        "notification_url": {"type": "string", "format": "uri"},
        "customer_code": {"type": "string", "maxLength": 50}
    }
}

# Payload
payload = {
    "due_date": "2024-12-31",
    "grace_period": 15,
    "amount": 100.50,
    "description": "Payment for services rendered",
    "metadata": [
        {"key": "order_id", "value": "ORD-2024-001"},
        {"key": "reference", "value": "REF-12345"}
    ],
    "payer": {
        "name": "João Silva",
        "document": "12345678901",
        "zip": "01234567",
        "street": "Rua das Flores",
        "city": "São Paulo",
        "state": "SP",
        "number": "123",
        "neighborhood": "Centro"
    },
    "fine": 2.5,
    "interest": 1.0,
    "discount": {
        "type": "fixed",
        "amount": 10.00,
        "limit_date": "2024-12-25"
    },
    "notification_url": "https://your-webhook.com/notifications",
    "customer_code": "CUST-001"
}

# Validar payload
try:
    validate(instance=payload, schema=schema)
except ValidationError as e:
    print(f"Erro de validação: {e}")
    exit(1)

# Enviar requisição
url = "https://sandbox-api.pagou.com.br/v1/charges"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}

try:
    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    print(f"Status: {response.status_code}")
    print(f"Location: {response.headers.get('Location')}")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                                       | Solução                                                |
| ----------- | --------------------- | ---------------------------------------------------- | ------------------------------------------------------ |
| 400         | Bad Request           | Payload inválido (ex.: CPF inválido, amount < 1.00). | Validar dados antes de enviar (use schema fornecido).  |
| 401         | Unauthorized          | X-API-KEY inválido ou ausente.                       | Verificar chave em *Configurações > API*.              |
| 429         | Too Many Requests     | Limite de requisições excedido.                      | Implementar rate limiting e retentativas exponenciais. |
| 500         | Internal Server Error | Erro interno da API.                                 | Tentar novamente e contatar <suporte@pagou.com.br>.    |

### Boas Práticas Técnicas

* **Validação de Dados**: Use esquemas JSON (como nos exemplos) para validar o payload antes de enviar, evitando erros 400.
* **Segurança**: Armazene X-API-KEY em variáveis de ambiente e use HTTPS para todas as requisições.
* **Webhooks**: Configure o `notification_url` para receber o evento <mark style="color:red;">`ChargePaid`</mark> quando o boleto for pago.
* **Testes no Sandbox**: Use <https://sandbox-api.pagou.com.br/v1/charge> para simular criação de boletos sem custos reais.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo Location) em logs para auditoria e depuração.

### Mapa de Status dos Boletos

Cada boleto possui um status que reflete seu estado no ciclo de vida. Os status possíveis, conforme definido na API do Pagou, são:

| **Status**                                       | **Valor Numérico** | **Descrição**                                                                                                                |
| ------------------------------------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| <mark style="color:red;">`StatusEmpty`</mark>    | 1                  | Estado inicial transitório, indicando que o boleto foi criado, mas ainda não está ativo (ex.: aguardando validação interna). |
| <mark style="color:red;">`StatusActive`</mark>   | 2                  | Boleto ativo, pronto para pagamento, com código de barras e PDF disponíveis.                                                 |
| <mark style="color:red;">`StatusCanceled`</mark> | 3                  | Boleto cancelado, não mais válido para pagamento (ex.: por solicitação ou expiração).                                        |
| <mark style="color:red;">`StatusPaid`</mark>     | 4                  | Boleto pago pelo cliente, com liquidação confirmada.                                                                         |
| <mark style="color:red;">`StatusRefunded`</mark> | 5                  | Boleto pago, mas reembolsado ao cliente (ex.: após devolução do produto).                                                    |

**Transições de Status**:

* `StatusEmpty` → `StatusActive`: Após validação interna bem-sucedida (geralmente imediata).
* `StatusActive` → `StatusPaid`: Quando o pagamento é confirmado (notificado via webhook `ChargePaid`).
* `StatusActive` → `StatusCanceled`: Após solicitação de cancelamento via solicitação ou expiração.
* `StatusPaid` → `StatusRefunded`: Após processamento de reembolso.
* `StatusEmpty`, `StatusCanceled`, `StatusRefunded`: Estados finais, sem transições adicionais.


# Consultando um Boleto

## Consultando um Boleto

A consulta de um boleto na API do Pagou permite recuperar detalhes de um boleto existente, como status, valor, código de barras e data de pagamento, usando seu ID único.&#x20;

### Visão Geral Técnica

O endpoint <mark style="color:purple;">`GET`</mark>` ``/v1/charges/{id}` retorna os detalhes completos de um boleto, incluindo informações do pagador, multas, juros, descontos e status. A operação é síncrona e ideal para verificar o estado de um boleto sem depender de webhooks, embora o uso de webhooks (ex.: evento `ChargePaid`) seja recomendado para atualizações automáticas.

<mark style="color:purple;">`GET`</mark> /v1/charges/{id}

### Cabeçalhos

| Cabeçalho      | Valor                    | Descrição                                                    |
| -------------- | ------------------------ | ------------------------------------------------------------ |
| `X-API-KEY`    | `sua_chave_api`          | Chave de autenticação (encontrada em *Configurações > API*). |
| `Content-Type` | `application/json`       | Formato JSON para a requisição.                              |
| `User-Agent`   | `NomeDaSuaAplicacao/1.0` | Identifica sua aplicação (ex.: `MinhaLoja/1.0`).             |

### Parâmetros da URL

| Parâmetro | Tipo   | Obrigatório | Descrição                                                       |
| --------- | ------ | ----------- | --------------------------------------------------------------- |
| `id`      | string | Sim         | ID único do boleto (ex.: 8325a4b3-579c-45df-b475-0ce57df2478d). |

**Validações**:

* `id`: Deve ser um ID válido retornado pelo endpoint de criação (<mark style="color:green;">`POST`</mark>` ``/v1/charges`).

### Resposta

* **Status**: `200 OK`
* **Corpo**: JSON com os detalhes do boleto.

**Exemplo de Resposta**:

```json
{
  "id": "8325a4b3-579c-45df-b475-0ce57df2478d",
  "status": 2,
  "due_date": "2024-12-31",
  "grace_period": 15,
  "amount": 100.50,
  "description": "Payment for services rendered",
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    },
    {
      "key": "reference",
      "value": "REF-12345"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901",
    "zip": "01234567",
    "street": "Rua das Flores",
    "city": "São Paulo",
    "state": "SP",
    "number": "123",
    "neighborhood": "Centro"
  },
  "fine": 2.5,
  "interest": 1.0,
  "discount": {
    "type": "fixed",
    "amount": 10.00,
    "limit_date": "2024-12-25"
  },
  "notification_url": "https://your-webhook.com/notifications",
  "customer_code": "CUST-001",
  "created_at": "2025-07-23T09:30:00-03:00",
  "paid_at": null
}
```

**Campos da Resposta**:

| Campo                 | Tipo   | Descrição                                                                   |
| --------------------- | ------ | --------------------------------------------------------------------------- |
| `id`                  | string | ID único do boleto (ex.: 8325a4b3-579c-45df-b475-0ce57df2478d).             |
| `status`              | number | Status do boleto (`1, 2, 3, 4, 5`).                                         |
| `due_date`            | string | Data de vencimento (formato `YYYY-MM-DD`).                                  |
| `grace_period`        | number | Dias de tolerância após o vencimento (ex.: 15).                             |
| `amount`              | number | Valor do boleto em reais (ex.: 100.50 para R$ 100,50).                      |
| `description`         | string | Descrição do boleto (máx. 255 caracteres).                                  |
| `metadata`            | array  | Pares chave-valor para dados adicionais (ex.: ID do pedido).                |
| `metadata[].key`      | string | Chave do metadado (ex.: `order_id`).                                        |
| `metadata[].value`    | string | Valor do metadado (ex.: `ORD-2024-001`).                                    |
| `payer`               | object | Dados do pagador.                                                           |
| `payer.name`          | string | Nome completo do pagador (máx. 100 caracteres).                             |
| `payer.document`      | string | CPF (11 dígitos) ou CNPJ (14 dígitos).                                      |
| `payer.zip`           | string | CEP (8 dígitos, sem hífen).                                                 |
| `payer.street`        | string | Rua ou avenida (máx. 200 caracteres).                                       |
| `payer.city`          | string | Cidade (máx. 100 caracteres).                                               |
| `payer.state`         | string | UF (2 letras, ex.: `SP`).                                                   |
| `payer.number`        | string | Número do endereço (máx. 20 caracteres).                                    |
| `payer.neighborhood`  | string | Bairro (máx. 100 caracteres).                                               |
| `fine`                | number | Multa por atraso em percentual (ex.: 2.5 para 2,5%).                        |
| `interest`            | number | Juros por dia de atraso em percentual (ex.: 1.0 para 1%).                   |
| `discount`            | object | Desconto para pagamento antecipado.                                         |
| `discount.type`       | string | Tipo de desconto (`fixed` ou `percentage`).                                 |
| `discount.amount`     | number | Valor do desconto (em reais para `fixed`, ou percentual para `percentage`). |
| `discount.limit_date` | string | Data limite para o desconto (formato `YYYY-MM-DD`).                         |
| `notification_url`    | string | URL HTTPS para webhooks (ex.: `https://your-webhook.com/notifications`).    |
| `customer_code`       | string | Código interno do cliente (máx. 50 caracteres).                             |
| `created_at`          | string | Data de criação do boleto (ISO 8601).                                       |
| `paid_at`             | string | Data de pagamento do boleto (ISO 8601, ou `null` se não pago).              |

### Exemplos de Código

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X GET https://sandbox-api.pagou.com.br/v1/charges/8325a4b3-579c-45df-b475-0ce57df2478d \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0"
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const fetch = require('node-fetch');
const { validate } = require('jsonschema');

// Esquema de validação da resposta
const schema = {
    type: 'object',
    required: ['id', 'status', 'due_date', 'amount', 'description', 'payer'],
    properties: {
        id: { type: 'string' },
        status: { type: 'number', enum: [1, 2, 3, 4, 5] },
        due_date: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
        grace_period: { type: 'integer', minimum: 0 },
        amount: { type: 'number', minimum: 1.00 },
        description: { type: 'string', maxLength: 255 },
        metadata: {
            type: 'array',
            items: {
                type: 'object',
                required: ['key', 'value'],
                properties: {
                    key: { type: 'string' },
                    value: { type: 'string' }
                }
            }
        },
        payer: {
            type: 'object',
            required: ['name', 'document', 'zip', 'street', 'city', 'state', 'number', 'neighborhood'],
            properties: {
                name: { type: 'string', maxLength: 100 },
                document: { type: 'string', pattern: '^\\d{11}|\\d{14}$' },
                zip: { type: 'string', pattern: '^\\d{8}$' },
                street: { type: 'string', maxLength: 200 },
                city: { type: 'string', maxLength: 100 },
                state: { type: 'string', pattern: '^[A-Z]{2}$' },
                number: { type: 'string', maxLength: 20 },
                neighborhood: { type: 'string', maxLength: 100 }
            }
        },
        fine: { type: 'number', minimum: 0, maximum: 100 },
        interest: { type: 'number', minimum: 0, maximum: 100 },
        discount: {
            type: 'object',
            required: ['type', 'amount', 'limit_date'],
            properties: {
                type: { type: 'string', enum: ['fixed', 'percentage'] },
                amount: { type: 'number', minimum: 0 },
                limit_date: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' }
            }
        },
        notification_url: { type: 'string', format: 'uri' },
        customer_code: { type: 'string', maxLength: 50 },
        barcode: { type: 'string' },
        pdf_url: { type: 'string', format: 'uri' },
        created_at: { type: 'string', format: 'date-time' },
        paid_at: { type: ['string', 'null'], format: 'date-time' }
    }
};

// Consultar boleto
const boletoId = '8325a4b3-579c-45df-b475-0ce57df2478d';
fetch(`https://sandbox-api.pagou.com.br/v1/charges/${boletoId}`, {
    method: 'GET',
    headers: {
        'X-API-KEY': 'sua_chave_api',
        'Content-Type': 'application/json',
        'User-Agent': 'MinhaLoja/1.0'
    }
})
    .then(response => {
        if (!response.ok) {
            throw new Error(`Erro ${response.status}: ${response.statusText}`);
        }
        return response.json();
    })
    .then(data => {
        // Validar resposta
        const validation = validate(data, schema);
        if (!validation.valid) {
            throw new Error(`Erro de validação: ${validation.errors}`);
        }
        
        console.log(`Boleto ID: ${data.id}`);
        console.log(`Status: ${data.status}`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
from jsonschema import validate, ValidationError

# Esquema de validação da resposta
schema = {
    "type": "object",
    "required": ["id", "status", "due_date", "amount", "description", "payer"],
    "properties": {
        "id": {"type": "string"},
        "status": {"type": "number", "enum": [1, 2, 3, 4, 5]},
        "due_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
        "grace_period": {"type": "integer", "minimum": 1},
        "amount": {"type": "number", "minimum": 1.00},
        "description": {"type": "string", "maxLength": 255},
        "metadata": {
            "type": "array",
            "items": {
                "type": "object",
                "required": ["key", "value"],
                "properties": {
                    "key": {"type": "string"},
                    "value": {"type": "string"}
                }
            }
        },
        "payer": {
            "type": "object",
            "required": ["name", "document", "zip", "street", "city", "state", "number", "neighborhood"],
            "properties": {
                "name": {"type": "string", "maxLength": 100},
                "document": {"type": "string", "pattern": "^\\d{11}|\\d{14}$"},
                "zip": {"type": "string", "pattern": "^\\d{8}$"},
                "street": {"type": "string", "maxLength": 200},
                "city": {"type": "string", "maxLength": 100},
                "state": {"type": "string", "pattern": "^[A-Z]{2}$"},
                "number": {"type": "string", "maxLength": 20},
                "neighborhood": {"type": "string", "maxLength": 100}
            }
        },
        "fine": {"type": "number", "minimum": 0, "maximum": 100},
        "interest": {"type": "number", "minimum": 0, "maximum": 100},
        "discount": {
            "type": "object",
            "required": ["type", "amount", "limit_date"],
            "properties": {
                "type": {"type": "string", "enum": ["fixed", "percentage"]},
                "amount": {"type": "number", "minimum": 0},
                "limit_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"}
            }
        },
        "notification_url": {"type": "string", "format": "uri"},
        "customer_code": {"type": "string", "maxLength": 50},
        "barcode": {"type": "string"},
        "pdf_url": {"type": "string", "format": "uri"},
        "created_at": {"type": "string", "format": "date-time"},
        "paid_at": {"type": ["string", "null"], "format": "date-time"}
    }
}

# Consultar boleto
boleto_id = "8325a4b3-579c-45df-b475-0ce57df2478d"
url = f"https://sandbox-api.pagou.com.br/v1/charges/{boleto_id}"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}

try:
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    data = response.json()
    
    # Validar resposta
    try:
        validate(instance=data, schema=schema)
    except ValidationError as e:
        print(f"Erro de validação na resposta: {e}")
        exit(1)
    
    print(f"Boleto ID: {data['id']}")
    print(f"Status: {data['status']}")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                   | Solução                                   |
| ----------- | --------------------- | -------------------------------- | ----------------------------------------- |
| `400`       | Bad Request           | ID do boleto malformado.         | Verificar formato do `id`.                |
| `401`       | Unauthorized          | `X-API-KEY` inválido ou ausente. | Verificar chave..                         |
| `404`       | Not Found             | Boleto não existe.               | Confirmar ID do boleto.                   |
| `429`       | Too Many Requests     | Limite de requisições excedido.  | Implementar rate limiting e retentativas. |
| `500`       | Internal Server Error | Erro interno da API.             | Tentar novamente e contatar suporte.      |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "Boleto not found"
}
```

### Boas Práticas Técnicas

* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Webhooks como Alternativa**: Para atualizações em tempo real, configure o evento `ChargePaid` em vez de consultas frequentes. Veja Webhooks para Interações com Boleto.
* **Testes no Sandbox**: Use `https://sandbox-api.pagou.com.br/v1/charges/{id}` para simular consultas sem custos reais.
* **Monitoramento**: Registre todas as requisições e respostas em logs, incluindo `id`, `status` e `paid_at`, para auditoria e depuração.
* **Cache**: Considere armazenar respostas em cache (ex.: Redis, com TTL de 5 minutos) para reduzir chamadas à API em sistemas de alto tráfego.

## Get a Charge

> This endpoint return a charge.

```json
{"openapi":"3.1.1","info":{"title":"Pagou API","version":"0.0.1"},"servers":[{"url":"https://sandbox-api.pagou.com.br"}],"security":[{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"XApiKeyAuth":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"models.ErrorResponse":{"type":"object","properties":{"error":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}}}},"paths":{"/v1/charges/{chargeID}":{"get":{"description":"This endpoint return a charge.","tags":["charges"],"summary":"Get a Charge","parameters":[{"type":"string","description":"Client Identifier","name":"User-Agent","in":"header"},{"type":"string","description":"Charge ID","name":"chargeID","in":"path","required":true}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"string"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}}}}}}}
```


# Cancelando um Boleto

## Cancelando um Boleto

O cancelamento de um boleto na API do Pagou permite invalidar um boleto ativo, alterando seu status para <mark style="color:red;background-color:red;">`StatusCanceled`</mark> e tornando-o não mais válido para pagamento.

### Visão Geral Técnica

O endpoint <mark style="color:red;">`DELETE`</mark>` ``/v1/charges/{chargeID}` solicita o cancelamento de um boleto identificado por seu ID único. A operação é síncrona, retornando `204 No Content` em caso de sucesso, indicando que o boleto foi cancelado e seu status atualizado para <mark style="color:red;">`StatusCanceled`</mark>. Apenas boletos no status <mark style="color:red;">`StatusActive`</mark> (ou, em casos raros, <mark style="color:red;">`StatusEmpty`</mark>) podem ser cancelados. Boletos em <mark style="color:red;">`StatusPaid`</mark>, <mark style="color:red;">`StatusRefunded`</mark> ou já em <mark style="color:red;background-color:red;">`StatusCanceled`</mark> não podem ser cancelados novamente.

**Especificações**:

* **Método**: DELETE
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/charges/{id}`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/charges/{id}`
* **Autenticação**: Cabeçalho X-API-KEY com chave do painel.
* **Content-Type**: `application/json`
* **Resposta**: Status `204 No Content` (sem corpo).
* **Erros**: 400 Bad Request, 401 Unauthorized, 500 Internal Server Error.

### Pré-requisitos

* **Conta no Pagou**: Acesse <https://pagou.com.br> e crie uma conta.
* **Chave de API**: Obtenha a chave em *Configurações > API* (diferentes para sandbox e produção).
* **ID do boleto**: Use o UUID retornado no header Location ao criar o boleto (ex.: 550e8400-e29b-41d4-a716-446655440000).
* **Ferramentas**: Use cURL, Postman ou bibliotecas HTTP (ex.: requests em Python, fetch em JavaScript).

### Endpoint

* **Método**: DELETE
* **URL**: <https://api.pagou.com.br/v1/charges/{id}> (produção) ou <https://sandbox-api.pagou.com.br/v1/charges/{id}> (sandbox)

### Cabeçalhos

| Cabeçalho    | Valor                  | Descrição                                                    |
| ------------ | ---------------------- | ------------------------------------------------------------ |
| X-API-KEY    | sua\_chave\_api        | Chave de autenticação (encontrada em *Configurações > API*). |
| Content-Type | application/json       | Formato JSON para a requisição.                              |
| User-Agent   | NomeDaSuaAplicacao/1.0 | Identificador da aplicação (ex.: MinhaLoja/1.0, opcional).   |

### Parâmetros da URL

| Parâmetro | Tipo   | Obrigatório | Descrição                                                                       |
| --------- | ------ | ----------- | ------------------------------------------------------------------------------- |
| `id`      | string | Sim         | ID único do boleto no formato UUID (ex.: 550e8400-e29b-41d4-a716-446655440000). |

**Validações**:

* id: Deve ser um UUID válido (ex.: 550e8400-e29b-41d4-a716-446655440000).
* O boleto deve estar em <mark style="color:red;">StatusActive</mark> ou, em casos raros, <mark style="color:red;">`StatusEmpty`</mark>. Boletos em outros status (ex.: <mark style="color:red;">StatusPaid</mark>) resultarão em erro 400.

### Resposta

* **Status**: 204 No Content
* **Corpo**: (Vazio, conforme padrão para 204).

**Exemplo de Resposta**:

```bash
HTTP/1.1 204 No Content
Content-Length: 0
```

### Mapa de Status e Cancelamento

O cancelamento altera o status do boleto para StatusCanceled. Abaixo está o contexto dos status, conforme definido na API do Pagou:

| Status           | Valor Numérico | Descrição                                                                                |
| ---------------- | -------------- | ---------------------------------------------------------------------------------------- |
| `StatusEmpty`    | 1              | Estado inicial transitório, indicando que o boleto foi criado, mas ainda não está ativo. |
| `StatusActive`   | 2              | Boleto ativo, pronto para pagamento, com código de barras e PDF disponíveis.             |
| `StatusCanceled` | 3              | Boleto cancelado, não mais válido para pagamento.                                        |
| `StatusPaid`     | 4              | Boleto pago pelo cliente, com liquidação confirmada.                                     |
| `StatusRefunded` | 5              | Boleto pago, mas reembolsado ao cliente.                                                 |

**Impacto do Cancelamento**:

* **Condição**: Apenas boletos em StatusActive (ou, raramente, StatusEmpty) podem ser cancelados.
* **Resultado**: O boleto transita para StatusCanceled, tornando-o inválido para pagamento.
* **Verificação**: Após o cancelamento, use <mark style="color:purple;">`GET`</mark>` ``/v1/charges/{id}` para confirmar o status <mark style="color:red;">StatusCanceled</mark> (veja Consultando um Boleto).
* **Webhooks**: O cancelamento não gera notificações via webhook.

### Exemplos de Código

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X DELETE https://sandbox-api.pagou.com.br/v1/charges/550e8400-e29b-41d4-a716-446655440000 \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0"
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');

// Configuração
const chargeId = '550e8400-e29b-41d4-a716-446655440000';
const url = `https://sandbox-api.pagou.com.br/v1/charges/${chargeId}`;
const headers = {
    'X-API-KEY': 'sua_chave_api',
    'Content-Type': 'application/json',
    'User-Agent': 'MinhaLoja/1.0'
};

fetch(url, {
    method: 'DELETE',
    headers: headers
})
    .then(response => {
        if (!response.ok) {
            return response.json().then(err => { throw new Error(`Erro ${response.status}: ${err.error.message}`); });
        }
        console.log(`Status: ${response.status} - Boleto ${chargeId} cancelado com sucesso`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import re

# Configuração
charge_id = "550e8400-e29b-41d4-a716-446655440000"
url = "https://sandbox-api.pagou.com.br/v1/charges/{charge_id}"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}

try:
    response = requests.delete(url, headers=headers)
    response.raise_for_status()
    print(f"Status: {response.status_code} - Boleto {charge_id} cancelado com sucesso")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
    if e.response:
        print(f"Detalhes: {e.response.json()}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                                                              | Solução                                                    |
| ----------- | --------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------- |
| 400         | Bad Request           | id não é um UUID válido ou boleto não está em `StatusActive`/`StatusEmpty`. | Verificar formato do id e status via GET /v1/charges/{id}. |
| 401         | Unauthorized          | `X-API-KEY` inválido ou ausente.                                            | Verificar chave.                                           |
| 500         | Internal Server Error | Erro interno da API.                                                        | Tentar novamente e contatar <suporte@pagou.com.br>.        |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "Charge is not in a cancellable state"
}
```

### Boas Práticas Técnicas

* **Validação de Dados**: Valide o id como UUID (formato 8-4-4-4-12) antes de enviar a requisição. Use <mark style="color:purple;">`GET`</mark>` ``/v1/charges/{id}` para confirmar se o boleto está em <mark style="color:red;">`StatusActive`</mark> antes de cancelar.
* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Verificação Pós-Cancelamento**: Após o cancelamento, consulte o boleto com <mark style="color:purple;">`GET`</mark>` ``/v1/charges/{id}` para confirmar o status StatusCanceled.
* **Testes no Sandbox**: Use `https://sandbox-api.pagou.com.br/v1/charges/{id}` para simular cancelamentos sem impacto em produção.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo id e status HTTP) em logs para auditoria e depuração.


# Webhooks

## Webhooks para Interações com Boletos

Os webhooks da API do Pagou permitem receber notificações assíncronas sobre eventos relacionados a boletos, como a criação ou confirmação de pagamento. Esta seção detalha os eventos <mark style="color:orange;">`charge.created`</mark> e <mark style="color:orange;">`charge.paid`</mark>, suas estruturas de payload, configuração do `notification_url`, autenticação, validação, exemplos de código, tratamento de erros e boas práticas para processar webhooks de forma robusta e segura.

### Visão Geral Técnica

A API do Pagou envia notificações via requisições HTTP POST para o `notification_url` configurado ao criar um boleto (via <mark style="color:green;">`POST`</mark> `/v1/charges`). Os eventos disponíveis para boletos são:

* <mark style="color:orange;">`charge.created`</mark>: Notifica quando um boleto é criado com sucesso, fornecendo detalhes como código de barras e linha digitável.
* <mark style="color:orange;">`charge.paid`</mark>: Notifica quando um boleto é pago, indicando que o pagamento foi confirmado.

Os webhooks são enviados em formato JSON e requerem um endpoint HTTPS público no lado do cliente para processamento. A API realiza até 10 tentativas de entrega do webhook, com intervalos exponenciais, até receber uma resposta 200 OK. Se o endpoint não responder com 200 OK, a API reenvia o webhook, exigindo que o processamento seja idempotente.

**Especificações**:

* **Método**: <mark style="color:green;">`POST`</mark>
* **Content-Type**: `application/json`
* **URL**: Configurada no campo `notification_url` ao criar o boleto.
* **Evento**: <mark style="color:orange;">`charge.paid`</mark>.
* **Reenvios**: Até **10 tentativas** até receber `200 OK`.

### Configuração do Webhook

1. **Definir o** `notification_url`: Ao criar um boleto via <mark style="color:green;">`POST`</mark>` ``/v1/charges`, inclua o campo `notification_url` (ex.: <https://your-webhook.com/notifications>) no corpo da requisição (veja [Criando um Boleto](/integracao-com-a-api/meio-de-pagamento-boleto/criando-um-boleto)).
2. **Implementar o endpoint**: Crie um endpoint HTTP `POST` no seu servidor para receber e processar os payloads JSON.
3. **Garantir HTTPS**: Use um certificado SSL válido para o `notification_url`.

### Estrutura do Webhook

#### Evento: charge.created

Notifica quando um boleto é criado com sucesso, fornecendo detalhes como código de barras e linha digitável.

**Payload**:

```json
{
  "name": "charge.created",
  "data": {
    "id": "6bd30949-248e-44c8-8b20-cca8bf6f2686",
    "transactionid": "22bf12b8-77fa-429f-b216-2accf48600eb",
    "clientcode": "6bd30949-248e-44c8-8b20-cca8bf6f2686",
    "payload": {
      "transaction_id": "32bf21d3-55fa-429f-b216-2accf48600ac",
      "bank_emissor": "CELCOIN INSTITUIÇÃO DE PAGAMENTO - SA",
      "bank_number": "1701112",
      "bank_agency": "0001",
      "bank_account": "999911111",
      "bar_code": "99990000000000099990000000000000000000000000",
      "line": "99990000000000000000000000000000000080000009999",
      "bank_assignor": "CELCOIN INSTITUIÇÃO DE PAGAMENTO - SA"
    }
  }
}
```

**Campos do Payload**:

| Campo                        | Tipo   | Descrição                                           |
| ---------------------------- | ------ | --------------------------------------------------- |
| name                         | string | Nome do evento (charge.created).                    |
| data                         | object | Dados do evento.                                    |
| data.id                      | string | ID do boleto.                                       |
| data.transactionid           | string | ID da transaçã.                                     |
| data.clientcode              | string | Identificador do ID do boleto.                      |
| data.payload                 | object | Detalhes do boleto.                                 |
| data.payload.transaction\_id | string | ID da transação, redundante com data.transactionid. |
| data.payload.bank\_emissor   | string | Nome da instituição emissora                        |
| data.payload.bank\_number    | string | Código do banco                                     |
| data.payload.bank\_agency    | string | Agência bancária                                    |
| data.payload.bank\_account   | string | Conta bancária.                                     |
| data.payload.bar\_code       | string | Código de barras do boleto.                         |
| data.payload.line            | string | Linha digitável do boleto.                          |
| data.payload.bank\_assignor  | string | Nome do cedente.                                    |

#### Evento: charge.paid

Notifica quando um boleto é pago, indicando que o pagamento foi confirmado.

**Payload**:

```json
{
  "name": "charge.paid",
  "data": {
    "id": "09cd8523-85e8-400f-9c06-3c1950714d6b",
    "transactionid": "a21b0b0f-e142-49e8-a81f-1095527f2ef2",
    "clientcode": "09cd8523-85e8-400f-9c06-3c1950714d6b",
    "amount": {
      "paid": 94.99,
      "original": 94.99
    },
    "paidin": "2025-07-23 08:00:06"
  }
}
```

**Campos do Payload**:

| Campo                | Tipo   | Descrição                                                                                         |
| -------------------- | ------ | ------------------------------------------------------------------------------------------------- |
| name                 | string | Nome do evento (charge.paid).                                                                     |
| data                 | object | Dados do evento.                                                                                  |
| data.id              | string | UUID do boleto (ex.: 09cd8523-85e8-400f-9c06-3c1950714d6b).                                       |
| data.transactionid   | string | ID da transação de pagamento (ex.: a21b0b0f-e142-49e8-a81f-1095527f2ef2).                         |
| data.clientcode      | string | Identificador do cliente (ex.: 09cd8523-85e8-400f-9c06-3c1950714d6b, equivalente a customer\_id). |
| data.amount          | object | Detalhes do valor do boleto.                                                                      |
| data.amount.paid     | number | Valor pago em reais (ex.: 94.99).                                                                 |
| data.amount.original | number | Valor original do boleto em reais (ex.: 94.99).                                                   |
| data.paidin          | string | Data e hora do pagamento (formato YYYY-MM-DD HH:MM:SS, ex.: 2025-07-23 08:00:06).                 |
| data.paymenttype     | string | Tipo de pagamento (ex.: vazio no exemplo, pode ser bank\_slip ou similar).                        |

**Resposta Esperada**:

* Retorne `200 OK` para confirmar o recebimento e evitar reenvios (até **10 tentativas** pela API).
* Outros códigos (ex.: 400, 401) acionam reenvios pela API do Pagou.


# Meio de Pagamento: Pix

{% openapi src="/files/qQQORCO54DSB83xSwPu7" path="/v1/pix" method="post" %}
[swagger.json](https://1531984135-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1aYQxJJrEOqi1xBa0bJL%2Fuploads%2FKax3MohVnD2iVqojDnGG%2Fswagger.json?alt=media\&token=27fd5a17-b704-47d7-8148-043f6b585530)
{% endopenapi %}

{% openapi src="/files/qQQORCO54DSB83xSwPu7" path="/v1/pix/{qrcodeID}" method="get" %}
[swagger.json](https://1531984135-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1aYQxJJrEOqi1xBa0bJL%2Fuploads%2FKax3MohVnD2iVqojDnGG%2Fswagger.json?alt=media\&token=27fd5a17-b704-47d7-8148-043f6b585530)
{% endopenapi %}

{% openapi src="/files/qQQORCO54DSB83xSwPu7" path="/v1/pix/{qrcodeID}/refund" method="delete" %}
[swagger.json](https://1531984135-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1aYQxJJrEOqi1xBa0bJL%2Fuploads%2FKax3MohVnD2iVqojDnGG%2Fswagger.json?alt=media\&token=27fd5a17-b704-47d7-8148-043f6b585530)
{% endopenapi %}

{% openapi src="/files/qQQORCO54DSB83xSwPu7" path="/v1/pix/{qrcodeID}" method="delete" %}
[swagger.json](https://1531984135-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1aYQxJJrEOqi1xBa0bJL%2Fuploads%2FKax3MohVnD2iVqojDnGG%2Fswagger.json?alt=media\&token=27fd5a17-b704-47d7-8148-043f6b585530)
{% endopenapi %}


# Criando um QRCode imediato

## Criando um QRCode imediato

A criação de um QRCode na API do Pagou permite gerar um código Pix dinâmico para pagamentos instantâneos.

### Visão Geral Técnica

O endpoint <mark style="color:green;">`POST`</mark>` ``/v1/pix` cria um QRCode para pagamento via Pix, com base nas informações fornecidas no payload JSON. O QRCode é identificado por um UUID único, retornado na resposta, e inclui um payload Pix e uma imagem em base64 para exibição. A operação é síncrona, retornando `201 Created` com os detalhes do QRCode, incluindo o código Pix (`payload.data`) e a imagem (`payload.image`). O pagamento pode ser monitorado via webhook (ex.: evento `ChargePaid`).

**Especificações**:

* **Método**: `POST`
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/pix`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/pix`
* **Autenticação**: Cabeçalho `X-API-KEY` com chave do painel.
* **Content-Type**: `application/json`
* **Resposta**: Status `201 Created` com corpo JSON contendo os detalhes do QRCode.
* **Erros**: `400 Bad Request`, `401 Unauthorized`, `500 Internal Server Error`.

### Cabeçalhos

| Cabeçalho      | Valor                    | Descrição                                                    |
| -------------- | ------------------------ | ------------------------------------------------------------ |
| `X-API-KEY`    | `sua_chave_api`          | Chave de autenticação.                                       |
| `Content-Type` | `application/json`       | Formato JSON para o corpo da requisição.                     |
| `User-Agent`   | `NomeDaSuaAplicacao/1.0` | Identificador da aplicação (ex.: `MinhaLoja/1.0`, opcional). |

### Corpo da Requisição

O payload deve conter informações do pagamento Pix, incluindo valor, descrição, pagador e configurações de notificação.

```json
{
  "amount": 50.00,
  "description": "Payment for product or service",
  "expiration": 3600,
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    },
    {
      "key": "reference",
      "value": "REF-12345"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901"
  },
  "notification_url": "https://your-webhook.com/notifications",
  "customer_code": "CUST-001"
}
```

**Campos do Payload**:

| Campo              | Tipo   | Obrigatório    | Descrição                                                                |
| ------------------ | ------ | -------------- | ------------------------------------------------------------------------ |
| `amount`           | number | Sim            | Valor do pagamento em reais (ex.: 50.00 para R$ 50,00).                  |
| `description`      | string | Sim            | Descrição do pagamento (máx. 255 caracteres).                            |
| `expiration`       | number | Sim            | Tempo de expiração do QRCode em segundos (ex.: 3600 para 1 hora).        |
| `metadata`         | array  | Não            | Pares chave-valor para dados adicionais (ex.: ID do pedido).             |
| `metadata[].key`   | string | Sim (se usado) | Chave do metadado (ex.: `order_id`).                                     |
| `metadata[].value` | string | Sim (se usado) | Valor do metadado (ex.: `ORD-2024-001`).                                 |
| `payer`            | object | Sim            | Dados do pagador.                                                        |
| `payer.name`       | string | Sim            | Nome completo do pagador (máx. 100 caracteres).                          |
| `payer.document`   | string | Sim            | CPF (11 dígitos) ou CNPJ (14 dígitos).                                   |
| `notification_url` | string | Não            | URL HTTPS para webhooks (ex.: `https://your-webhook.com/notifications`). |
| `customer_code`    | string | Não            | Código interno do cliente (máx. 50 caracteres).                          |

**Validações**:

* `amount`: Valor mínimo de 5 (R$ 5,00).
* `description`: Máximo de 255 caracteres.
* `expiration`: Valor positivo, geralmente entre 60 (1 minuto) e 604800 (7 dias).
* `payer.document`: Deve ser um CPF (11 dígitos) ou CNPJ (14 dígitos) válido.
* `notification_url`: Deve ser uma URL HTTPS válida.

### Resposta

* **Status**: `201 Created`
* **Corpo**: JSON com os detalhes do QRCode, incluindo o UUID, payload Pix e imagem em base64.

**Exemplo de Resposta**:

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 50.00,
  "description": "Payment for product or service",
  "expiration": 3600,
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    },
    {
      "key": "reference",
      "value": "REF-12345"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901"
  },
  "notification_url": "https://your-webhook.com/notifications",
  "customer_code": "CUST-001",
  "payload": {
    "payload_id": 12345,
    "data": "00020126580014br.gov.bcb.pix0136123e4567-e12b-12d1-a456-426614174000520400005303986540550.005802BR5913JOAO SILVA6008SAO PAULO62070503***6304ABCD",
    "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVHic7doxAQAAAMKg9U9tCj+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4GvAAAEAAQ=="
  }
}
```

**Campos da Resposta**:

| Campo                | Tipo   | Descrição                                                           |
| -------------------- | ------ | ------------------------------------------------------------------- |
| `id`                 | string | UUID único do QRCode (ex.: `550e8400-e29b-41d4-a716-446655440000`). |
| `amount`             | number | Valor do pagamento em reais (ex.: 50.00).                           |
| `description`        | string | Descrição do pagamento (máx. 255 caracteres).                       |
| `expiration`         | number | Tempo de expiração do QRCode em segundos (ex.: 3600).               |
| `metadata`           | array  | Pares chave-valor para dados adicionais.                            |
| `metadata[].key`     | string | Chave do metadado (ex.: `order_id`).                                |
| `metadata[].value`   | string | Valor do metadado (ex.: `ORD-2024-001`).                            |
| `payer`              | object | Dados do pagador.                                                   |
| `payer.name`         | string | Nome completo do pagador (máx. 100 caracteres).                     |
| `payer.document`     | string | CPF (11 dígitos) ou CNPJ (14 dígitos).                              |
| `notification_url`   | string | URL HTTPS para webhooks.                                            |
| `customer_code`      | string | Código interno do cliente (máx. 50 caracteres).                     |
| `payload`            | object | Dados do QRCode Pix.                                                |
| `payload.payload_id` | number | ID interno do payload Pix.                                          |
| `payload.data`       | string | Código Pix para pagamento (copia-e-cola).                           |
| `payload.image`      | string | Imagem do QRCode em base64 (formato `data:image/png;base64,...`).   |

### Exemplos de Código

#### cURL

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://sandbox-api.pagou.com.br/v1/pix \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0" \
  -H "Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000" \
  -d '{
    "amount": 50.00,
    "description": "Payment for product or service",
    "expiration": 3600,
    "metadata": [
      {
        "key": "order_id",
        "value": "ORD-2024-001"
      },
      {
        "key": "reference",
        "value": "REF-12345"
      }
    ],
    "payer": {
      "name": "João Silva",
      "document": "12345678901"
    },
    "notification_url": "https://your-webhook.com/notifications",
    "customer_code": "CUST-001"
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');
const { validate } = require('jsonschema');

// Esquema de validação do payload
const schema = {
    type: 'object',
    required: ['amount', 'description', 'expiration', 'payer'],
    properties: {
        amount: { type: 'number', minimum: 0.01 },
        description: { type: 'string', maxLength: 255 },
        expiration: { type: 'integer', minimum: 300, maximum: 604800 },
        metadata: {
            type: 'array',
            items: {
                type: 'object',
                required: ['key', 'value'],
                properties: {
                    key: { type: 'string' },
                    value: { type: 'string' }
                }
            }
        },
        payer: {
            type: 'object',
            required: ['name', 'document'],
            properties: {
                name: { type: 'string', maxLength: 100 },
                document: { type: 'string', pattern: '^\\d{11}|\\d{14}$' }
            }
        },
        notification_url: { type: 'string', format: 'uri' },
        customer_code: { type: 'string', maxLength: 50 }
    }
};

// Payload
const payload = {
    amount: 50.00,
    description: 'Payment for product or service',
    expiration: 3600,
    metadata: [
        { key: 'order_id', value: 'ORD-2024-001' },
        { key: 'reference', value: 'REF-12345' }
    ],
    payer: {
        name: 'João Silva',
        document: '12345678901'
    },
    notification_url: 'https://your-webhook.com/notifications',
    customer_code: 'CUST-001'
};

// Validar payload
const validation = validate(payload, schema);
if (!validation.valid) {
    console.error('Erro de validação:', validation.errors);
    process.exit(1);
}

// Enviar requisição
fetch('https://sandbox-api.pagou.com.br/v1/pix', {
    method: 'POST',
    headers: {
        'X-API-KEY': 'sua_chave_api',
        'Content-Type': 'application/json',
        'User-Agent': 'MinhaLoja/1.0',
        'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000'
    },
    body: JSON.stringify(payload)
})
    .then(response => {
        if (!response.ok) {
            return response.json().then(err => { throw new Error(`Erro ${response.status}: ${err.error.message}`); });
        }
        return response.json();
    })
    .then(data => {
        console.log(`QRCode ID: ${data.id}`);
        console.log(`Código Pix: ${data.payload.data}`);
        console.log(`Imagem Base64: ${data.payload.image}`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
from jsonschema import validate, ValidationError
import re

# Esquema de validação do payload
schema = {
    "type": "object",
    "required": ["amount", "description", "expiration", "payer"],
    "properties": {
        "amount": {"type": "number", "minimum": 0.01},
        "description": {"type": "string", "maxLength": 255},
        "expiration": {"type": "integer", "minimum": 300, "maximum": 604800},
        "metadata": {
            "type": "array",
            "items": {
                "type": "object",
                "required": ["key", "value"],
                "properties": {
                    "key": {"type": "string"},
                    "value": {"type": "string"}
                }
            }
        },
        "payer": {
            "type": "object",
            "required": ["name", "document"],
            "properties": {
                "name": {"type": "string", "maxLength": 100},
                "document": {"type": "string", "pattern": "^\\d{11}|\\d{14}$"}
            }
        },
        "notification_url": {"type": "string", "format": "uri"},
        "customer_code": {"type": "string", "maxLength": 50}
    }
}

# Payload
payload = {
    "amount": 50.00,
    "description": "Payment for product or service",
    "expiration": 3600,
    "metadata": [
        {"key": "order_id", "value": "ORD-2024-001"},
        {"key": "reference", "value": "REF-12345"}
    ],
    "payer": {
        "name": "João Silva",
        "document": "12345678901"
    },
    "notification_url": "https://your-webhook.com/notifications",
    "customer_code": "CUST-001"
}

# Validar payload
try:
    validate(instance=payload, schema=schema)
except ValidationError as e:
    print(f"Erro de validação: {e}")
    exit(1)

# Enviar requisição
url = "https://sandbox-api.pagou.com.br/v1/pix"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0",
    "Idempotency-Key": "123e4567-e89b-12d3-a456-426614174000"
}

try:
    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    data = response.json()
    print(f"QRCode ID: {data['id']}")
    print(f"Código Pix: {data['payload']['data']}")
    print(f"Imagem Base64: {data['payload']['image']}")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
    if e.response:
        print(f"Detalhes: {e.response.json()}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                                                                      | Solução                                                                          |
| ----------- | --------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `400`       | Bad Request           | Payload inválido (ex.: CPF inválido, `amount` < 5, `expiration` fora do intervalo). | Validar dados antes de enviar (use schema fornecido).                            |
| `401`       | Unauthorized          | `X-API-KEY` inválido ou ausente.                                                    | Verificar chave..                                                                |
| `500`       | Internal Server Error | Erro interno da API.                                                                | Tentar novamente e contatar [contato@pagou.com.br](mailto:suporte@pagou.com.br). |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "amount must be greater than or equal to 0.01"
}
```

### Mapa de Status do Pix

Cada QRCode Pix com vencimento possui um status que reflete seu estado no ciclo de vida. Os status possíveis, conforme definido na API do Pagou, são:

| Status                                               | Valor Numérico | Descrição                                                                                                                    |
| ---------------------------------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| <mark style="color:orange;">`StatusEmpty`</mark>     | 1              | Estado inicial transitório, indicando que o QRCode foi criado, mas ainda não está ativo (ex.: aguardando validação interna). |
| <mark style="color:orange;">`StatusActive`</mark>    | 2              | QRCode ativo, pronto para pagamento, com código Pix e imagem disponíveis.                                                    |
| <mark style="color:orange;">`StatusCanceled`</mark>  | 3              | QRCode cancelado, não mais válido para pagamento (ex.: por solicitação ou expiração).                                        |
| <mark style="color:orange;">`StatusCompleted`</mark> | 4              | QRCode pago pelo cliente, com liquidação confirmada.                                                                         |
| <mark style="color:orange;">`StatusRefunded`</mark>  | 5              | QRCode pago, mas reembolsado ao cliente (ex.: após devolução do produto).                                                    |

**Transições de Status**:

* <mark style="color:orange;">`StatusEmpty`</mark> → <mark style="color:orange;">`StatusActive`</mark>: Após validação interna bem-sucedida (geralmente imediata).
* <mark style="color:orange;">`StatusActive`</mark> → <mark style="color:orange;">`StatusCompleted`</mark>: Quando o pagamento é confirmado (notificado via webhook <mark style="color:orange;">`QRCodeCompleted`</mark>).
* <mark style="color:orange;">`StatusActive`</mark> → <mark style="color:orange;">`StatusCanceled`</mark>: Após solicitação de cancelamento (ex.: <mark style="color:red;">`DELETE`</mark>` ``/v1/pix/{id}`) ou expiração do QRCode (definida por `due_date` e `expiration`).
* <mark style="color:orange;">`StatusCompleted`</mark> → <mark style="color:orange;">`StatusRefunded`</mark>: Após processamento de reembolso (se aplicável).
* <mark style="color:orange;">`StatusCanceled`</mark>, <mark style="color:orange;">`StatusRefunded`</mark>: Estados finais, sem transições adicionais.

### Boas Práticas Técnicas

* **Validação de Dados**: Use esquemas JSON (como nos exemplos) para validar o payload antes de enviar, evitando erros `400`.
* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Webhooks**: Configure o `notification_url` para receber o evento <mark style="color:orange;">`QRCodeCompleted`</mark> ou <mark style="color:orange;">`QRCodeRefunded`</mark> quando o pagamento for confirmado ou estornado.
* **Testes no Sandbox**: Use `https://sandbox-api.pagou.com.br/v1/pix` para simular criação de QRCodes sem custos reais.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo `id`, `payload.data` e `payload.image`) em logs para auditoria e depuração.

## Create a QRCode

> This endpoint creates a new qrcode with the provided data.

```json
{"openapi":"3.1.1","info":{"title":"Pagou API","version":"0.0.1"},"servers":[{"url":"https://sandbox-api.pagou.com.br"}],"security":[{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"XApiKeyAuth":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"models.ErrorResponse":{"type":"object","properties":{"error":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"models.CreateQRCodeRequest":{"type":"object","required":["amount","description","expiration","payer"],"properties":{"amount":{"type":"number"},"customer_code":{"type":"string"},"description":{"type":"string"},"expiration":{"type":"integer","minimum":60},"metadata":{"type":"array","items":{"$ref":"#/components/schemas/models.QRCodeMetadata"}},"notification_url":{"type":"string"},"payer":{"$ref":"#/components/schemas/models.QRCodePayer"}}},"models.QRCodeMetadata":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}}},"models.QRCodePayer":{"type":"object","required":["document","name"],"properties":{"document":{"type":"string"},"name":{"type":"string"}}}}},"paths":{"/v1/pix":{"post":{"description":"This endpoint creates a new qrcode with the provided data.","tags":["pix"],"summary":"Create a QRCode","parameters":[{"type":"string","description":"Client Identifier","name":"User-Agent","in":"header"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"string"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreateQRCodeRequest"}}},"description":"QRCode data","required":true}}}}}
```

## Create a QRCode with due

> This endpoint creates a new qrcode due with the provided data.

```json
{"openapi":"3.1.1","info":{"title":"Pagou API","version":"0.0.1"},"servers":[{"url":"https://sandbox-api.pagou.com.br"}],"security":[{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"XApiKeyAuth":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"models.ErrorResponse":{"type":"object","properties":{"error":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"models.CreateQRCodeDueRequest":{"type":"object","required":["amount","description","due_date","expiration","payer"],"properties":{"amount":{"type":"number"},"description":{"type":"string"},"discount":{"$ref":"#/components/schemas/models.DiscountQRCodeDueInfo"},"due_date":{"type":"string"},"expiration":{"type":"integer","minimum":1},"fine":{"$ref":"#/components/schemas/models.QRCodeDueInfo"},"interest":{"$ref":"#/components/schemas/models.QRCodeDueInfo"},"metadata":{"type":"array","items":{"$ref":"#/components/schemas/models.QRCodeMetadata"}},"notification_url":{"type":"string"},"payer":{"$ref":"#/components/schemas/models.QRCodePayer"}}},"models.DiscountQRCodeDueInfo":{"type":"object","required":["amount","limit_date","type"],"properties":{"amount":{"type":"number"},"limit_date":{"type":"string"},"type":{"description":"TODO: check it after","type":"string","enum":["fixed","percentage","fixed_calendar_days","fixed_working_days","percentage_calendar_days","percentage_working_days","percentage_month_calendar_days","percentage_month_working_days","percentage_year_calendar_days","percentage_year_working_days"]}}},"models.QRCodeDueInfo":{"type":"object","required":["amount","type"],"properties":{"amount":{"type":"number"},"type":{"description":"TODO: check it after","type":"string","enum":["fixed","percentage","fixed_calendar_days","fixed_working_days","percentage_calendar_days","percentage_working_days","percentage_month_calendar_days","percentage_month_working_days","percentage_year_calendar_days","percentage_year_working_days"]}}},"models.QRCodeMetadata":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}}},"models.QRCodePayer":{"type":"object","required":["document","name"],"properties":{"document":{"type":"string"},"name":{"type":"string"}}}}},"paths":{"/v1/pix/due":{"post":{"description":"This endpoint creates a new qrcode due with the provided data.","tags":["pix"],"summary":"Create a QRCode with due","parameters":[{"type":"string","description":"Client Identifier","name":"User-Agent","in":"header"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"string"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreateQRCodeDueRequest"}}},"description":"QRCode data","required":true}}}}}
```


# Criando um QRCode com vencimento

## Criando um QRCode com vencimento

A criação de um QRCode com vencimento na API do Pagou permite gerar um código Pix dinâmico com data de vencimento, ideal para pagamentos que requerem multas, juros ou descontos, similar a um boleto.

### Visão Geral Técnica

O endpoint <mark style="color:green;">`POST`</mark>` ``/v1/pix/due` cria um QRCode Pix com data de vencimento, com base nas informações fornecidas no payload JSON. O QRCode é identificado por um UUID único, retornado na resposta, e inclui um payload Pix e uma imagem em base64 para exibição. A operação é síncrona, retornando `201 Created` com os detalhes do QRCode, incluindo o código Pix (`payload.data`) e a imagem (`payload.image`). O pagamento pode ser monitorado via webhook (ex.: evento <mark style="color:orange;">`QRCodeCompleted`</mark> e <mark style="color:orange;">`QRCodeRefunded`</mark>).

**Especificações**:

* **Método**: `POST`
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/pix/due`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/pix/due`
* **Autenticação**: Cabeçalho `X-API-KEY` com chave do painel.
* **Content-Type**: `application/json`
* **Resposta**: Status `201 Created` com corpo JSON contendo os detalhes do QRCode.
* **Erros**: `400 Bad Request`, `401 Unauthorized`, `500 Internal Server Error`.

### Cabeçalhos

| Cabeçalho      | Valor                    | Descrição                                          |
| -------------- | ------------------------ | -------------------------------------------------- |
| `X-API-KEY`    | `sua_chave_api`          | Chave de autenticação.                             |
| `Content-Type` | `application/json`       | Formato JSON para o corpo da requisição.           |
| `User-Agent`   | `NomeDaSuaAplicacao/1.0` | Identificador da aplicação (ex.: `MinhaLoja/1.0`). |

### Corpo da Requisição

O payload deve conter informações do pagamento Pix, incluindo valor, descrição, data de vencimento, pagador, multas, juros, descontos e configurações de notificação.

```json
{
  "amount": 100.00,
  "description": "Payment with due date",
  "expiration": 30,
  "due_date": "2024-12-31",
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    },
    {
      "key": "invoice_number",
      "value": "INV-12345"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901"
  },
  "discount": {
    "type": "fixed",
    "amount": 10.00,
    "limit_date": "2024-12-25"
  },
  "fine": {
    "type": "percentage",
    "amount": 2.5
  },
  "interest": {
    "type": "percentage_calendar_days",
    "amount": 1.0
  },
  "notification_url": "https://your-webhook.com/notifications"
}
```

**Campos do Payload**:

| Campo                 | Tipo   | Obrigatório    | Descrição                                                                   |
| --------------------- | ------ | -------------- | --------------------------------------------------------------------------- |
| `amount`              | number | Sim            | Valor do pagamento em reais (ex.: 100.00 para R$ 100,00).                   |
| `description`         | string | Sim            | Descrição do pagamento (máx. 255 caracteres).                               |
| `expiration`          | number | Sim            | Tempo de expiração do QRCode em dias (mínimo 1).                            |
| `due_date`            | string | Sim            | Data de vencimento (formato `YYYY-MM-DD`).                                  |
| `metadata`            | array  | Não            | Pares chave-valor para dados adicionais (ex.: ID do pedido).                |
| `metadata[].key`      | string | Sim (se usado) | Chave do metadado (ex.: `order_id`).                                        |
| `metadata[].value`    | string | Sim (se usado) | Valor do metadado (ex.: `ORD-2024-001`).                                    |
| `payer`               | object | Sim            | Dados do pagador.                                                           |
| `payer.name`          | string | Sim            | Nome completo do pagador (máx. 100 caracteres).                             |
| `payer.document`      | string | Sim            | CPF (11 dígitos) ou CNPJ (14 dígitos).                                      |
| `discount`            | object | Não            | Desconto para pagamento antecipado.                                         |
| `discount.type`       | string | Sim (se usado) | Tipo de desconto (`fixed`, `percentage`, `fixed_calendar_days`, etc.).      |
| `discount.amount`     | number | Sim (se usado) | Valor do desconto (em reais para `fixed`, ou percentual para `percentage`). |
| `discount.limit_date` | string | Sim (se usado) | Data limite para o desconto (formato `YYYY-MM-DD`).                         |
| `fine`                | object | Não            | Multa por atraso.                                                           |
| `fine.type`           | string | Sim (se usado) | Tipo de multa (`percentage`, `fixed`, etc.).                                |
| `fine.amount`         | number | Sim (se usado) | Valor da multa (em percentual ou reais).                                    |
| `interest`            | object | Não            | Juros por atraso.                                                           |
| `interest.type`       | string | Sim (se usado) | Tipo de juros (`percentage_calendar_days`, `fixed`, etc.).                  |
| `interest.amount`     | number | Sim (se usado) | Valor dos juros (em percentual ou reais).                                   |
| `notification_url`    | string | Não            | URL HTTPS para webhooks (ex.: `https://your-webhook.com/notifications`).    |

**Validações**:

* `amount`: Valor mínimo de 5 (R$ 5,00).
* `description`: Máximo de 255 caracteres.
* `expiration`: Valor inteiro maior ou igual a 60 (em segundos).
* `due_date`: Deve ser uma data futura (mín. 1 dia após a criação, formato `YYYY-MM-DD`).
* `payer.document`: Deve ser um CPF (11 dígitos) ou CNPJ (14 dígitos) válido.
* `discount.limit_date`: Deve ser anterior a `due_date`.
* `discount.amount`: Deve ser menor que `amount`.
* `fine.amount` e `interest.amount`: Devem ser menores que `amount`.
* `notification_url`: Deve ser uma URL HTTPS válida.

**Notas Técnicas**:

* O status inicial após a criação (`201 Created`) é tipicamente <mark style="color:orange;">`StatusEmpty`</mark>, transitando rapidamente para <mark style="color:orange;">`StatusActive`</mark> após validação.
* Use o endpoint <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}` para consultar o status atual.
* Configure o `notification_url` no payload para receber o evento `QRCodeCompleted` quando o status mudar para <mark style="color:orange;">`StatusCompleted`</mark> ou <mark style="color:orange;">`QRCodeRefunded`</mark> quando o status mudar para <mark style="color:orange;">`StatusRefunded`</mark>
* O campo `expiration` define o período em dias após o qual o QRCode expira automaticamente, transitando para `StatusCanceled` se não pago até `due_date`.

### Resposta

* **Status**: `201 Created`
* **Corpo**: JSON com os detalhes do QRCode, incluindo o UUID, payload Pix e imagem em base64.

**Exemplo de Resposta**:

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 100.00,
  "description": "Payment with due date",
  "expiration": 30,
  "due_date": "2024-12-31",
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    },
    {
      "key": "invoice_number",
      "value": "INV-12345"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901"
  },
  "discount": {
    "type": "fixed",
    "amount": 10.00,
    "limit_date": "2024-12-25"
  },
  "fine": {
    "type": "percentage",
    "amount": 2.5
  },
  "interest": {
    "type": "percentage_calendar_days",
    "amount": 1.0
  },
  "notification_url": "https://your-webhook.com/notifications",
  "payload": {
    "payload_id": 12345,
    "data": "00020126580014br.gov.bcb.pix0136123e4567-e12b-12d1-a456-426614174000520400005303986540100.005802BR5913JOAO SILVA6008SAO PAULO62070503***63041234",
    "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVHic7doxAQAAAMKg9U9tCj+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4GvAAAEAAQ=="
  }
}
```

**Campos da Resposta**:

| Campo                 | Tipo   | Descrição                                                                     |
| --------------------- | ------ | ----------------------------------------------------------------------------- |
| `id`                  | string | UUID único do QRCode (ex.: `550e8400-e29b-41d4-a716-446655440000`).           |
| `amount`              | number | Valor do pagamento em reais (ex.: 100.00).                                    |
| `description`         | string | Descrição do pagamento (máx. 255 caracteres).                                 |
| `expiration`          | number | Tempo de expiração do QRCode em dias (ex.: 30).                               |
| `due_date`            | string | Data de vencimento (formato `YYYY-MM-DD`).                                    |
| `metadata`            | array  | Pares chave-valor para dados adicionais.                                      |
| `metadata[].key`      | string | Chave do metadado (ex.: `order_id`).                                          |
| `metadata[].value`    | string | Valor do metadado (ex.: `ORD-2024-001`).                                      |
| `payer`               | object | Dados do pagador.                                                             |
| `payer.name`          | string | Nome completo do pagador (máx. 100 caracteres).                               |
| `payer.document`      | string | CPF (11 dígitos) ou CNPJ (14 dígitos).                                        |
| `discount`            | object | Desconto para pagamento antecipado.                                           |
| `discount.type`       | string | Tipo de desconto (`fixed`, `percentage`, `fixed_calendar_days`).              |
| `discount.amount`     | number | Valor do desconto (em reais ou percentual).                                   |
| `discount.limit_date` | string | Data limite para o desconto (formato `YYYY-MM-DD`).                           |
| `fine`                | object | Multa por atraso.                                                             |
| `fine.type`           | string | Tipo de multa (`percentage ou` `fixed`.).                                     |
| `fine.amount`         | number | Valor da multa (em percentual ou reais).                                      |
| `interest`            | object | Juros por atraso.                                                             |
| `interest.type`       | string | Tipo de juros (`percentage_calendar_days`, `fixed`, `fixed` ou `percentage`). |
| `interest.amount`     | number | Valor dos juros (em percentual ou reais).                                     |
| `notification_url`    | string | URL HTTPS para webhooks.                                                      |
| `payload`             | object | Dados do QRCode Pix.                                                          |
| `payload.payload_id`  | number | ID interno do payload Pix.                                                    |
| `payload.data`        | string | Código Pix para pagamento (copia-e-cola).                                     |
| `payload.image`       | string | Imagem do QRCode em base64 (formato `data:image/png;base64,...`).             |

### Exemplos de Código

{% tabs %}
{% tab title="cURL" %}

```ruby
curl -X POST https://sandbox-api.pagou.com.br/v1/pix/due \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0" \
  -d '{
    "amount": 100.00,
    "description": "Payment with due date",
    "expiration": 30,
    "due_date": "2024-12-31",
    "metadata": [
      {
        "key": "order_id",
        "value": "ORD-2024-001"
      },
      {
        "key": "invoice_number",
        "value": "INV-12345"
      }
    ],
    "payer": {
      "name": "João Silva",
      "document": "12345678901"
    },
    "discount": {
      "type": "fixed",
      "amount": 10.00,
      "limit_date": "2024-12-25"
    },
    "fine": {
      "type": "percentage",
      "amount": 2.5
    },
    "interest": {
      "type": "percentage_calendar_days",
      "amount": 1.0
    },
    "notification_url": "https://your-webhook.com/notifications"
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');
const { validate } = require('jsonschema');

// Esquema de validação do payload
const schema = {
    type: 'object',
    required: ['amount', 'description', 'expiration', 'due_date', 'payer'],
    properties: {
        amount: { type: 'number', minimum: 0.01 },
        description: { type: 'string', maxLength: 255 },
        expiration: { type: 'integer', minimum: 1 },
        due_date: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
        metadata: {
            type: 'array',
            items: {
                type: 'object',
                required: ['key', 'value'],
                properties: {
                    key: { type: 'string' },
                    value: { type: 'string' }
                }
            }
        },
        payer: {
            type: 'object',
            required: ['name', 'document'],
            properties: {
                name: { type: 'string', maxLength: 100 },
                document: { type: 'string', pattern: '^\\d{11}|\\d{14}$' }
            }
        },
        discount: {
            type: 'object',
            required: ['type', 'amount', 'limit_date'],
            properties: {
                type: { type: 'string', enum: ['fixed', 'percentage', 'fixed_calendar_days'] },
                amount: { type: 'number', minimum: 0 },
                limit_date: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' }
            }
        },
        fine: {
            type: 'object',
            required: ['type', 'amount'],
            properties: {
                type: { type: 'string', enum: ['percentage', 'fixed'] },
                amount: { type: 'number', minimum: 0 }
            }
        },
        interest: {
            type: 'object',
            required: ['type', 'amount'],
            properties: {
                type: { type: 'string', enum: ['percentage_calendar_days', 'fixed'] },
                amount: { type: 'number', minimum: 0 }
            }
        },
        notification_url: { type: 'string', format: 'uri' }
    }
};

// Payload
const payload = {
    amount: 100.00,
    description: 'Payment with due date',
    expiration: 30,
    due_date: '2024-12-31',
    metadata: [
        { key: 'order_id', value: 'ORD-2024-001' },
        { key: 'invoice_number', value: 'INV-12345' }
    ],
    payer: {
        name: 'João Silva',
        document: '12345678901'
    },
    discount: {
        type: 'fixed',
        amount: 10.00,
        limit_date: '2024-12-25'
    },
    fine: {
        type: 'percentage',
        amount: 2.5
    },
    interest: {
        type: 'percentage_calendar_days',
        amount: 1.0
    },
    notification_url: 'https://your-webhook.com/notifications'
};

// Validar payload
const validation = validate(payload, schema);
if (!validation.valid) {
    console.error('Erro de validação:', validation.errors);
    process.exit(1);
}

// Validar due_date como data futura
const dueDate = new Date(payload.due_date);
if (dueDate <= new Date()) {
    console.error('Erro: due_date must be a future date');
    process.exit(1);
}
// Validar discount.limit_date <= due_date
if (payload.discount && payload.discount.limit_date) {
    const limitDate = new Date(payload.discount.limit_date);
    if (limitDate > dueDate) {
        console.error('Erro: discount.limit_date must be before or equal to due_date');
        process.exit(1);
    }
}
// Validar discount.amount, fine.amount e interest.amount < amount
if (payload.discount && payload.discount.amount >= payload.amount) {
    console.error('Erro: discount.amount must be less than amount');
    process.exit(1);
}
if (payload.fine && payload.fine.amount >= payload.amount) {
    console.error('Erro: fine.amount must be less than amount');
    process.exit(1);
}
if (payload.interest && payload.interest.amount >= payload.amount) {
    console.error('Erro: interest.amount must be less than amount');
    process.exit(1);
}

// Enviar requisição
fetch('https://sandbox-api.pagou.com.br/v1/pix/due', {
    method: 'POST',
    headers: {
        'X-API-KEY': 'sua_chave_api',
        'Content-Type': 'application/json',
        'User-Agent': 'MinhaLoja/1.0'
    },
    body: JSON.stringify(payload)
})
    .then(response => {
        if (!response.ok) {
            return response.json().then(err => { throw new Error(`Erro ${response.status}: ${err.error.message}`); });
        }
        return response.json();
    })
    .then(data => {
        console.log(`QRCode ID: ${data.id}`);
        console.log(`Status: ${data.status}`);
        console.log(`Código Pix: ${data.payload.data}`);
        console.log(`Imagem Base64: ${data.payload.image}`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
from jsonschema import validate, ValidationError
import re
from datetime import datetime

# Esquema de validação do payload
schema = {
    "type": "object",
    "required": ["amount", "description", "expiration", "due_date", "payer"],
    "properties": {
        "amount": {"type": "number", "minimum": 0.01},
        "description": {"type": "string", "maxLength": 255},
        "expiration": {"type": "integer", "minimum": 1},
        "due_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
        "metadata": {
            "type": "array",
            "items": {
                "type": "object",
                "required": ["key", "value"],
                "properties": {
                    "key": {"type": "string"},
                    "value": {"type": "string"}
                }
            }
        },
        "payer": {
            "type": "object",
            "required": ["name", "document"],
            "properties": {
                "name": {"type": "string", "maxLength": 100},
                "document": {"type": "string", "pattern": "^\\d{11}|\\d{14}$"}
            }
        },
        "discount": {
            "type": "object",
            "required": ["type", "amount", "limit_date"],
            "properties": {
                "type": {"type": "string", "enum": ["fixed", "percentage", "fixed_calendar_days"]},
                "amount": {"type": "number", "minimum": 0},
                "limit_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"}
            }
        },
        "fine": {
            "type": "object",
            "required": ["type", "amount"],
            "properties": {
                "type": {"type": "string", "enum": ["percentage", "fixed"]},
                "amount": {"type": "number", "minimum": 0}
            }
        },
        "interest": {
            "type": "object",
            "required": ["type", "amount"],
            "properties": {
                "type": {"type": "string", "enum": ["percentage_calendar_days", "fixed"]},
                "amount": {"type": "number", "minimum": 0}
            }
        },
        "notification_url": {"type": "string", "format": "uri"}
    }
}

# Payload
payload = {
    "amount": 100.00,
    "description": "Payment with due date",
    "expiration": 30,
    "due_date": "2024-12-31",
    "metadata": [
        {"key": "order_id", "value": "ORD-2024-001"},
        {"key": "invoice_number", "value": "INV-12345"}
    ],
    "payer": {
        "name": "João Silva",
        "document": "12345678901"
    },
    "discount": {
        "type": "fixed",
        "amount": 10.00,
        "limit_date": "2024-12-25"
    },
    "fine": {
        "type": "percentage",
        "amount": 2.5
    },
    "interest": {
        "type": "percentage_calendar_days",
        "amount": 1.0
    },
    "notification_url": "https://your-webhook.com/notifications"
}

# Validar payload
try:
    validate(instance=payload, schema=schema)
    # Validar due_date como data futura
    due_date = datetime.strptime(payload["due_date"], "%Y-%m-%d")
    if due_date <= datetime.now():
        raise ValueError("due_date must be a future date")
    # Validar discount.limit_date <= due_date
    if "discount" in payload and payload["discount"].get("limit_date"):
        limit_date = datetime.strptime(payload["discount"]["limit_date"], "%Y-%m-%d")
        if limit_date > due_date:
            raise ValueError("discount.limit_date must be before or equal to due_date")
    # Validar discount.amount, fine.amount e interest.amount < amount
    if "discount" in payload and payload["discount"].get("amount", 0) >= payload["amount"]:
        raise ValueError("discount.amount must be less than amount")
    if "fine" in payload and payload["fine"].get("amount", 0) >= payload["amount"]:
        raise ValueError("fine.amount must be less than amount")
    if "interest" in payload and payload["interest"].get("amount", 0) >= payload["amount"]:
        raise ValueError("interest.amount must be less than amount")
except (ValidationError, ValueError) as e:
    print(f"Erro de validação: {e}")
    exit(1)

# Enviar requisição
url = "https://sandbox-api.pagou.com.br/v1/pix/due"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}

try:
    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    data = response.json()
    print(f"QRCode ID: {data['id']}")
    print(f"Status: {data.get('status', 'StatusEmpty')}")
    print(f"Código Pix: {data['payload']['data']}")
    print(f"Imagem Base64: {data['payload']['image']}")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
    if e.response:
        print(f"Detalhes: {e.response.json()}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                                                                                                                                  | Solução                                                                           |
| ----------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `400`       | Bad Request           | Payload inválido (ex.: CPF inválido, `amount` < 5, `due_date` no passado, `discount.limit_date` após `due_date`, `discount.amount` ≥ `amount`). | Validar dados antes de enviar.                                                    |
| `401`       | Unauthorized          | `X-API-KEY` inválido ou ausente.                                                                                                                | Verificar chave.                                                                  |
| `500`       | Internal Server Error | Erro interno da API.                                                                                                                            | Tentar novamente e contatar [scontato@pagou.com.br](mailto:suporte@pagou.com.br). |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "discount.limit_date must be before or equal to due_date"
}
```

### Mapa de Status do Pix

Cada QRCode Pix com vencimento possui um status que reflete seu estado no ciclo de vida. Os status possíveis, conforme definido na API do Pagou, são:

| Status                                               | Valor Numérico | Descrição                                                                                                                    |
| ---------------------------------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| <mark style="color:orange;">`StatusEmpty`</mark>     | 1              | Estado inicial transitório, indicando que o QRCode foi criado, mas ainda não está ativo (ex.: aguardando validação interna). |
| <mark style="color:orange;">`StatusActive`</mark>    | 2              | QRCode ativo, pronto para pagamento, com código Pix e imagem disponíveis.                                                    |
| <mark style="color:orange;">`StatusCanceled`</mark>  | 3              | QRCode cancelado, não mais válido para pagamento (ex.: por solicitação ou expiração).                                        |
| <mark style="color:orange;">`StatusCompleted`</mark> | 4              | QRCode pago pelo cliente, com liquidação confirmada.                                                                         |
| <mark style="color:orange;">`StatusRefunded`</mark>  | 5              | QRCode pago, mas reembolsado ao cliente (ex.: após devolução do produto).                                                    |

**Transições de Status**:

* <mark style="color:orange;">`StatusEmpty`</mark> → <mark style="color:orange;">`StatusActive`</mark>: Após validação interna bem-sucedida (geralmente imediata).
* <mark style="color:orange;">`StatusActive`</mark> → <mark style="color:orange;">`StatusCompleted`</mark>: Quando o pagamento é confirmado (notificado via webhook <mark style="color:orange;">`QRCodeCompleted`</mark>).
* <mark style="color:orange;">`StatusActive`</mark> → <mark style="color:orange;">`StatusCanceled`</mark>: Após solicitação de cancelamento (ex.: <mark style="color:red;">`DELETE`</mark>` ``/v1/pix/{id}`) ou expiração do QRCode (definida por `due_date` e `expiration`).
* <mark style="color:orange;">`StatusCompleted`</mark> → <mark style="color:orange;">`StatusRefunded`</mark>: Após processamento de reembolso (se aplicável).
* <mark style="color:orange;">`StatusCanceled`</mark>, <mark style="color:orange;">`StatusRefunded`</mark>: Estados finais, sem transições adicionais.

### Boas Práticas Técnicas

* **Validação de Dados**: Use esquemas JSON (como nos exemplos) para validar o payload antes de enviar, incluindo verificações específicas como `due_date` futura, `discount.limit_date` ≤ `due_date` e `discount.amount`, `fine.amount`, `interest.amount` < `amount`.
* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Status do Pix**: Após a criação, verifique o status com <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}` (a ser documentado) para confirmar a transição de <mark style="color:red;">`StatusEmpty`</mark> para <mark style="color:red;">`StatusActive`</mark>.
* **Webhooks**: Configure o `notification_url` para receber o evento <mark style="color:red;">`QRCodeCompleted`</mark> quando o status mudar para <mark style="color:red;">`StatusCompleted`</mark> ou <mark style="color:red;">`QRCodeRefunded`</mark> quando o status mudar para <mark style="color:red;">`StatusRefunded`</mark>.
* **Testes no Sandbox**: Use `https://sandbox-api.pagou.com.br/v1/pix/due` para simular criação de QRCodes sem custos reais.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo `id`, `status`, `payload.data` e `payload.image`) em logs para auditoria e depuração.


# Consultando um QRCode

A consulta de um QRCode na API do Pagou permite obter os detalhes de um QRCode Pix (com ou sem vencimento), incluindo seu status, valor, pagador e código Pix.

### Visão Geral Técnica

O endpoint <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}` retorna os detalhes de um QRCode identificado por seu ID único no formato UUID (ex.: 550e8400-e29b-41d4-a716-446655440000). A operação é síncrona, retornando `200 OK` com um corpo JSON contendo informações como status, valor, pagador, código Pix e imagem em base64. Este endpoint é útil para verificar o estado de um pagamento Pix (ex.: pago ou expirado) ou recuperar o código Pix para exibição.

**Especificações**:

* **Método**: GET
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/pix/{qrcodeID}`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/pix/{qrcodeID}`
* **Autenticação**: Cabeçalho X-API-KEY com chave do painel.
* **Content-Type**: `application/json`
* **Resposta**: Status `200 OK` com corpo JSON contendo os detalhes do QRCode.
* **Erros**: 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error.

### Cabeçalhos

| Cabeçalho      | Valor                  | Descrição                                        |
| -------------- | ---------------------- | ------------------------------------------------ |
| `X-API-KEY`    | sua\_chave\_api        | Chave de autenticação.                           |
| `Content-Type` | application/json       | Formato JSON para a requisição.                  |
| `User-Agent`   | NomeDaSuaAplicacao/1.0 | Identificador da aplicação (ex.: MinhaLoja/1.0). |

### Parâmetros da URL

| Parâmetro | Tipo   | Obrigatório | Descrição                                                                       |
| --------- | ------ | ----------- | ------------------------------------------------------------------------------- |
| `id`      | string | Sim         | ID único do QRCode no formato UUID (ex.: 550e8400-e29b-41d4-a716-446655440000). |

**Validações**:

* qrcodeID: Deve ser um UUID válido (ex.: 550e8400-e29b-41d4-a716-446655440000).

**Notas Técnicas**:

* Configure o `notification_url` ao criar o QRCode para receber o evento <mark style="color:orange;">`QRCodeCompleted`</mark> quando o status mudar para <mark style="color:orange;">`StatusCompleted`</mark> ou <mark style="color:orange;">`QRCodeRefunded`</mark> quando o status mudar para <mark style="color:orange;">`StatusRefunded`</mark>.

### Resposta

* **Status**: 200 OK
* **Corpo**: JSON com os detalhes do QRCode, incluindo status, valor, pagador, código Pix e imagem em base64.

**Exemplo de Resposta**:

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "customer_id": "cust-12345",
  "amount": 100.00,
  "description": "Payment with due date",
  "expiration": 30,
  "due_date": "2024-12-31",
  "status": "active",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z",
  "metadata": [
    {
      "key": "order_id",
      "value": "ORD-2024-001"
    }
  ],
  "payer": {
    "name": "João Silva",
    "document": "12345678901"
  },
  "discount": {
    "type": "fixed",
    "amount": 10.00,
    "limit_date": "2024-12-25"
  },
  "fine": {
    "type": "percentage",
    "amount": 2.5
  },
  "interest": {
    "type": "percentage_calendar_days",
    "amount": 1.0
  },
  "notification_url": "https://your-webhook.com/notifications",
  "payload": {
    "payload_id": 12345,
    "data": "00020126580014br.gov.bcb.pix0136123e4567-e12b-12d1-a456-426614174000520400005303986540100.005802BR5913JOAO SILVA6008SAO PAULO62070503***63041234",
    "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVHic7doxAQAAAMKg9U9tCj+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4GvAAAEAAQ=="
  }
}
```

**Campos da Resposta**:

| **Campo**             | **Tipo** | **Descrição**                                                                                         |
| --------------------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `id`                  | string   | UUID único do QRCode (ex.: 550e8400-e29b-41d4-a716-446655440000).                                     |
| `customer_id`         | string   | Identificador interno do cliente (ex.: cust-12345).                                                   |
| `amount`              | number   | Valor do pagamento em reais (ex.: 100.00).                                                            |
| `description`         | string   | Descrição do pagamento (máx. 255 caracteres).                                                         |
| `expiration`          | number   | Tempo de expiração do QRCode (em dias para QRCodes com vencimento, ou segundos para QRCodes simples). |
| `due_date`            | string   | Data de vencimento, se aplicável (formato YYYY-MM-DD).                                                |
| `status`              | string   | Status atual do QRCode (empty, active, canceled, completed, refunded).                                |
| `created_at`          | string   | Data de criação do QRCode (formato ISO 8601).                                                         |
| `updated_at`          | string   | Data da última atualização (formato ISO 8601).                                                        |
| `metadata`            | array    | Pares chave-valor para dados adicionais.                                                              |
| `metadata[].key`      | string   | Chave do metadado (ex.: order\_id).                                                                   |
| `metadata[].value`    | string   | Valor do metadado (ex.: ORD-2024-001).                                                                |
| `payer`               | object   | Dados do pagador.                                                                                     |
| `payer.name`          | string   | Nome completo do pagador (máx. 100 caracteres).                                                       |
| payer.document        | string   | CPF (11 dígitos) ou CNPJ (14 dígitos).                                                                |
| `discount`            | object   | Desconto para pagamento antecipado, se aplicável.                                                     |
| `discount.type`       | string   | Tipo de desconto (fixed, percentage, fixed\_calendar\_days).                                          |
| `discount.amount`     | number   | Valor do desconto (em reais ou percentual).                                                           |
| `discount.limit_date` | string   | Data limite para o desconto (formato YYYY-MM-DD).                                                     |
| `fine`                | object   | Multa por atraso, se aplicável.                                                                       |
| `fine.type`           | string   | Tipo de multa (percentage, fixed, etc.).                                                              |
| `fine.amount`         | number   | Valor da multa (em percentual ou reais).                                                              |
| `interest`            | object   | Juros por atraso, se aplicável.                                                                       |
| `interest.type`       | string   | Tipo de juros (percentage\_calendar\_days, fixed, percentage.).                                       |
| `interest.amount`     | number   | Valor dos juros (em percentual ou reais).                                                             |
| `notification_url`    | string   | URL HTTPS para webhooks.                                                                              |
| `payload`             | object   | Dados do QRCode Pix.                                                                                  |
| `payload.payload_id`  | number   | ID interno do payload Pix.                                                                            |
| `payload.data`        | string   | Código Pix para pagamento (copia-e-cola).                                                             |
| `payload.image`       | string   | Imagem do QRCode em base64 (formato data:image/png;base64,...).                                       |

### Exemplos de Código

{% tabs %}
{% tab title="cURL" %}

```ruby
curl -X GET https://sandbox-api.pagou.com.br/v1/pix/550e8400-e29b-41d4-a716-446655440000 \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0"
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');

// Configuração
const qrcodeId = '550e8400-e29b-41d4-a716-446655440000';
const url = `https://sandbox-api.pagou.com.br/v1/pix/${qrcodeId}`;
const headers = {
    'X-API-KEY': 'sua_chave_api',
    'Content-Type': 'application/json',
    'User-Agent': 'MinhaLoja/1.0'
};

fetch(url, {
    method: 'GET',
    headers: headers
})
    .then(response => {
        if (!response.ok) {
            return response.json().then(err => { throw new Error(`Erro ${response.status}: ${err.error.message}`); });
        }
        return response.json();
    })
    .then(data => {
        console.log(`QRCode ID: ${data.id}`);
        console.log(`Status: ${data.status}`);
        console.log(`Valor: ${data.amount}`);
        console.log(`Código Pix: ${data.payload.data}`);
        console.log(`Imagem Base64: ${data.payload.image}`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import re

# Configuração
qrcode_id = "550e8400-e29b-41d4-a716-446655440000"
url = f"https://sandbox-api.pagou.com.br/v1/pix/{qrcode_id}"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}

try:
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    data = response.json()
    print(f"QRCode ID: {data['id']}")
    print(f"Status: {data['status']}")
    print(f"Valor: {data['amount']}")
    print(f"Código Pix: {data['payload']['data']}")
    print(f"Imagem Base64: {data['payload']['image']}")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
    if e.response:
        print(f"Detalhes: {e.response.json()}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                 | Solução                                             |
| ----------- | --------------------- | ------------------------------ | --------------------------------------------------- |
| 400         | Bad Request           | id não é um UUID válido.       | Verificar formato do id.                            |
| 401         | Unauthorized          | X-API-KEY inválido ou ausente. | Verificar chave.                                    |
| 404         | Not Found             | QRCode com o id não existe.    | Verificar o id fornecido.                           |
| 500         | Internal Server Error | Erro interno da API.           | Tentar novamente e contatar <contato@pagou.com.br>. |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "QRCode not found"
}
```

### Boas Práticas Técnicas

* **Validação de Dados**: Valide o id como UUID antes de enviar a requisição.
* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo id, status, payload.data e payload.image) em logs para auditoria e depuração.
* **Testes no Sandbox**: Use `https://sandbox-api.pagou.com.br/v1/pix/{id}` para simular consultas sem impacto em produção.
* **Uso da Imagem**: Converta o campo payload.image (base64) em uma imagem PNG para exibição em interfaces (ex.: \<img src="{payload.image}"> em HTML).
* **Verificação de Status**: Use o campo status para determinar ações subsequentes (ex.: exibir o código Pix se active, ou notificar o usuário se canceled)


# Cancelando um QRCode

## Cancelando um QRCode

O cancelamento de um QRCode na API do Pagou permite invalidar um QRCode Pix ativo (com ou sem vencimento), tornando-o não mais utilizável para pagamento. .

### Visão Geral Técnica

O endpoint <mark style="color:red;">`DELETE`</mark>` ``/v1/pix/{id}` solicita o cancelamento de um QRCode identificado por seu ID único no formato UUID (ex.: 550e8400-e29b-41d4-a716-446655440000). A operação é síncrona, retornando `204 No Content` para indicar que o cancelamento foi bem-sucedido, e o status do QRCode é alterado para <mark style="color:orange;">`StatusCanceled`</mark>. Este endpoint é útil para invalidar QRCodes antes de sua expiração ou em caso de erro na criação.

**Especificações**:

* **Método**: <mark style="color:red;">`DELETE`</mark>
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/pix/{id}`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/pix/{id}`
* **Autenticação**: Cabeçalho `X-API-KEY` com chave do painel.
* **Content-Type**: `application/json`
* **Resposta**: Status `204 No Content` sem corpo.
* **Erros**: 400 Bad Request, 401 Unauthorized, 500 Internal Server Error.

### Cabeçalhos

| Cabeçalho      | Valor                  | Descrição                                        |
| -------------- | ---------------------- | ------------------------------------------------ |
| `X-API-KEY`    | sua\_chave\_api        | Chave de autenticação.                           |
| `Content-Type` | application/json       | Formato JSON para a requisição.                  |
| `User-Agent`   | NomeDaSuaAplicacao/1.0 | Identificador da aplicação (ex.: MinhaLoja/1.0). |

### Parâmetros da URL

| Parâmetro | Tipo   | Obrigatório | Descrição                                                                       |
| --------- | ------ | ----------- | ------------------------------------------------------------------------------- |
| `id`      | string | Sim         | ID único do QRCode no formato UUID (ex.: 550e8400-e29b-41d4-a716-446655440000). |

**Validações**:

* O QRCode deve estar no status <mark style="color:orange;">`StatusActive`</mark> para ser cancelado. QRCodes em <mark style="color:orange;">`StatusEmpty`</mark>, <mark style="color:orange;">`StatusCanceled`</mark>, <mark style="color:orange;">`StatusCompleted`</mark> ou <mark style="color:orange;">`StatusRefunded`</mark> não podem ser cancelados.

**Notas Técnicas**:

* O endpoint <mark style="color:red;">`DELETE`</mark>` ``/v1/pix/{id}` transita o status do QRCode de <mark style="color:orange;">`StatusActive`</mark> para StatusCanceled.
* QRCodes em estados diferentes de <mark style="color:orange;">`StatusActive`</mark> (ex.: <mark style="color:orange;">`StatusCompleted`</mark>, <mark style="color:orange;">`StatusCanceled`</mark>) resultarão em erro 400 Bad Request.

### Resposta

* **Status**: 204 No Content
* **Corpo**: Nenhum (a resposta não contém corpo, indicando sucesso no cancelamento).

### Exemplos de Código

{% tabs %}
{% tab title="cURL" %}

```ruby
curl -X DELETE https://sandbox-api.pagou.com.br/v1/pix/550e8400-e29b-41d4-a716-446655440000 \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0"
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');

// Configuração
const qrcodeId = '550e8400-e29b-41d4-a716-446655440000';
const url = `https://sandbox-api.pagou.com.br/v1/pix/${qrcodeId}`;
const headers = {
    'X-API-KEY': 'sua_chave_api',
    'Content-Type': 'application/json',
    'User-Agent': 'MinhaLoja/1.0'
};

fetch(url, {
    method: 'DELETE',
    headers: headers
})
    .then(response => {
        if (!response.ok) {
            return response.json().then(err => { throw new Error(`Erro ${response.status}: ${err.error.message}`); });
        }
        console.log(`QRCode ${qrcodeId} cancelado com sucesso`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import re

# Configuração
qrcode_id = "550e8400-e29b-41d4-a716-446655440000"
url = f"https://sandbox-api.pagou.com.br/v1/pix/{qrcode_id}"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}

try:
    response = requests.delete(url, headers=headers)
    response.raise_for_status()
    print(f"QRCode {qrcode_id} cancelado com sucesso")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
    if e.response:
        print(f"Detalhes: {e.response.json()}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                                                     | Solução                                                                                                   |
| ----------- | --------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| 400         | Bad Request           | id não é um UUID válido ou QRCode não está no status StatusActive. | Verificar formato do id e consultar status com <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}`. |
| 401         | Unauthorized          | `X-API-KEY` inválido ou ausente.                                   | Verificar chave.                                                                                          |
| 500         | Internal Server Error | Erro interno da API.                                               | Tentar novamente e contatar <contato@pagou.com.br>.                                                       |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "QRCode is not in active status"
}
```

### Boas Práticas Técnicas

* **Verificação Prévia**: Consulte o status do QRCode com GET /v1/pix/{id} (veja Consultando um QRCode) para confirmar que está em StatusActive antes de tentar cancelar.
* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo id e código de status HTTP) em logs para auditoria e depuração.
* **Confirmação de Cancelamento**: Após o cancelamento, use <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}` para verificar se o status mudou para StatusCanceled.
* **Testes no Sandbox**: Use `https://sandbox-api.pagou.com.br/v1/pix/{id}` para simular cancelamentos sem impacto em produção.
* **Gestão de Erros**: Trate erros 400 para evitar tentativas de cancelamento de QRCodes já pagos (<mark style="color:orange;">`StatusCompleted`</mark>) ou cancelados (<mark style="color:orange;">`StatusCanceled`</mark>).


# Estornando um QRCode

## Estornando um QRCode

O estorno de um QRCode na API do Pagou permite solicitar o reembolso de um QRCode Pix pago (com ou sem vencimento), transitando seu status para <mark style="color:orange;">`StatusRefunded`</mark>.

### Visão Geral Técnica

O endpoint <mark style="color:red;">`DELETE`</mark>` ``/v1/pix/{id}/refund` solicita o estorno de um QRCode identificado por seu ID único no formato UUID (ex.: 550e8400-e29b-41d4-a716-446655440000). O payload permite especificar o valor do estorno (para estornos parciais) e o motivo do reembolso. A operação é síncrona, retornando `204 No Content` para indicar que o estorno foi iniciado com sucesso, e o status do QRCode é alterado para <mark style="color:orange;">`StatusRefunded`</mark>.

**Especificações**:

* **Método**: <mark style="color:red;">`DELETE`</mark>
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/pix/{id}/refund`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/pix/{id}/refund`
* **Autenticação**: Cabeçalho `X-API-KEY` com chave do painel.
* **Content-Type**: application/json
* **Resposta**: Status `204 No Content` sem corpo.
* **Erros**: `400 Bad Request`, `401 Unauthorized`, `500 Internal Server Error`.

### Cabeçalhos

| Cabeçalho      | Valor                  | Descrição                                                    |
| -------------- | ---------------------- | ------------------------------------------------------------ |
| `X-API-KEY`    | sua\_chave\_api        | Chave de autenticação (encontrada em *Configurações > API*). |
| `Content-Type` | application/json       | Formato JSON para o corpo da requisição.                     |
| `User-Agent`   | NomeDaSuaAplicacao/1.0 | Identificador da aplicação (ex.: MinhaLoja/1.0, opcional).   |

### Parâmetros da URL

| Parâmetro | Tipo   | Obrigatório | Descrição                                                                       |
| --------- | ------ | ----------- | ------------------------------------------------------------------------------- |
| `id`      | string | Sim         | ID único do QRCode no formato UUID (ex.: 550e8400-e29b-41d4-a716-446655440000). |

### Corpo da Requisição

O payload deve conter informações do estorno, como o valor a ser reembolsado (para estornos parciais) e o motivo do reembolso.

```json
{
  "amount": 50.00,
  "reason": 3,
  "description": "Customer requested refund due to product return"
}
```

**Campos do Payload**:

| Campo         | Tipo   | Obrigatório | Descrição                                                                |
| ------------- | ------ | ----------- | ------------------------------------------------------------------------ |
| `amount`      | number | Sim         | Valor do estorno em reais (ex.: 50.00 para R$ 50,00).                    |
| `reason`      | number | Sim         | Motivo do estorno. Valores válidos: `1`, `2`, `3`, `4`.                  |
| `description` | string | Sim         | Descrição do estorno (máx. 255 caracteres, ex.: "Devolução do produto"). |

**Valores de** reason:

<table data-header-hidden><thead><tr><th width="374"></th><th></th></tr></thead><tbody><tr><td>Valor</td><td>Descrição</td></tr><tr><td>1</td><td>Estorno devido a um erro bancário.</td></tr><tr><td>2</td><td>Estorno por suspeita de fraude.</td></tr><tr><td>3</td><td>Estorno solicitado pelo cliente final.</td></tr><tr><td>4</td><td>Estorno devido a erro relacionado ao Pix Saque ou Pix Troco.</td></tr></tbody></table>

**Validações**:

* id: Deve ser um UUID válido (ex.: 550e8400-e29b-41d4-a716-446655440000).
* amount: Deve ser maior que 0 e menor ou igual ao valor original do QRCode.
* reason: Máximo de 255 caracteres, se fornecido.
* O QRCode deve estar no status <mark style="color:orange;">`StatusCompleted`</mark>. QRCodes em <mark style="color:orange;">`StatusEmpty`</mark>, <mark style="color:orange;">`StatusActive`</mark>, <mark style="color:orange;">`StatusCanceled`</mark> ou <mark style="color:orange;">`StatusRefunded`</mark> não podem ser estornados.

**Notas Técnicas**:

* Use o endpoint <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}` ([veja Consultando um QRCode](/integracao-com-a-api/meio-de-pagamento-pix/consultando-um-qrcode)) para verificar o status do QRCode antes e após o estorno.
* O estorno pode ser parcial ou total.
* Configure o `notification_url` ao criar o QRCode para receber eventos relacionados ao pagamento ou estorno, se aplicável (veja Webhooks para Interações com Pix).

### Resposta

* **Status**: `204 No Content`
* **Corpo**: Nenhum (a resposta não contém corpo, indicando sucesso no início do processo de estorno).

### Exemplos de Código

####

{% tabs %}
{% tab title="cURL" %}

```ruby
curl -X DELETE https://sandbox-api.pagou.com.br/v1/pix/550e8400-e29b-41d4-a716-446655440000/refund \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0" \
  -d '{
    "amount": 50.00,
    "reason": "Customer requested refund due to product return"
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');
const { validate } = require('jsonschema');

// Esquema de validação do payload
const schema = {
    type: 'object',
    properties: {
        amount: { type: 'number', minimum: 0.01 },
        reason: { type: 'string', maxLength: 255 }
    }
};

// Configuração
const qrcodeId = '550e8400-e29b-41d4-a716-446655440000';
const url = `https://sandbox-api.pagou.com.br/v1/pix/${qrcodeId}/refund`;
const headers = {
    'X-API-KEY': 'sua_chave_api',
    'Content-Type': 'application/json',
    'User-Agent': 'MinhaLoja/1.0'
};
const payload = {
    amount: 50.00,
    reason: 'Customer requested refund due to product return'
};

// Validar payload
const validation = validate(payload, schema);
if (!validation.valid) {
    console.error('Erro de validação:', validation.errors);
    process.exit(1);
}

fetch(url, {
    method: 'DELETE',
    headers: headers,
    body: JSON.stringify(payload)
})
    .then(response => {
        if (!response.ok) {
            return response.json().then(err => { throw new Error(`Erro ${response.status}: ${err.error.message}`); });
        }
        console.log(`Estorno do QRCode ${qrcodeId} iniciado com sucesso`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import re
from jsonschema import validate, ValidationError

# Esquema de validação do payload
schema = {
    "type": "object",
    "properties": {
        "amount": {"type": "number", "minimum": 0.01},
        "reason": {"type": "string", "maxLength": 255}
    }
}

# Configuração
qrcode_id = "550e8400-e29b-41d4-a716-446655440000"
url = f"https://sandbox-api.pagou.com.br/v1/pix/{qrcode_id}/refund"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}
payload = {
    "amount": 50.00,
    "reason": "Customer requested refund due to product return"
}

# Validar payload
try:
    validate(instance=payload, schema=schema)
except ValidationError as e:
    print(f"Erro de validação: {e}")
    exit(1)

try:
    response = requests.delete(url, json=payload, headers=headers)
    response.raise_for_status()
    print(f"Estorno do QRCode {qrcode_id} iniciado com sucesso")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
    if e.response:
        print(f"Detalhes: {e.response.json()}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                                                                                                     | Solução                                                                                                                   |
| ----------- | --------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| 400         | Bad Request           | id não é um UUID válido, amount inválido (ex.: maior que o valor original), ou QRCode não está em StatusCompleted. | Verificar formato do id, validar amount e consultar status com <mark style="color:orange;">`GET`</mark>` ``/v1/pix/{id}`. |
| 401         | Unauthorized          | `X-API-KEY` inválido ou ausente.                                                                                   | Verificar chave.                                                                                                          |
| 500         | Internal Server Error | Erro interno da API.                                                                                               | Tentar novamente e contatar <contato@pagou.com.ver>                                                                       |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "QRCode is not in completed status"
}
```

### Boas Práticas Técnicas

* **Verificação Prévia**: Consulte o status do QRCode com <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}` (veja Consultando um QRCode) para confirmar que está em <mark style="color:orange;">`StatusCompleted`</mark> antes de tentar estornar.
* **Validação de Dados**: Valide o id como UUID e o amount (se fornecido) como menor ou igual ao valor original do QRCode antes de enviar a requisição.
* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo id e código de status HTTP) em logs para auditoria e depuração.
* **Confirmação de Estorno**: Após o estorno, use <mark style="color:purple;">`GET`</mark>` ``/v1/pix/{id}` para verificar se o status mudou para StatusRefunded.
* **Testes no Sandbox**: Use `https://sandbox-api.pagou.com.br/v1/pix/{id}/refund` para simular estornos sem impacto em produção.
* **Gestão de Erros**: Trate erros 400 para evitar tentativas de estorno de QRCodes não pagos (<mark style="color:orange;">`StatusActive`</mark>) ou já estornados (<mark style="color:orange;">`StatusRefunded`</mark>).


# Webhooks

## Webhooks para Interações com Pix

Os webhooks da API do Pagou permitem receber notificações assíncronas sobre eventos relacionados a QRCodes Pix, como pagamentos confirmados ou estornos processados. Esta seção detalha os eventos <mark style="color:orange;">`qrcode.completed`</mark> e <mark style="color:orange;">`qrcode.refunded`</mark>, suas estruturas de payload, configuração do `notification_url`.

### Visão Geral Técnica

A API do Pagou envia notificações via requisições HTTP `POST` para o `notification_url` configurado ao criar um QRCode Pix (via <mark style="color:green;">`POST`</mark>` ``/v1/pix` ou <mark style="color:green;">`POST`</mark>` ``/v1/pix/due`). Dois eventos estão disponíveis para Pix:

* **qrcode.completed**: Notifica quando um QRCode Pix é pago, transitando o status para <mark style="color:orange;">`StatusCompleted`</mark>.
* **qrcode.refunded**: Notifica quando um QRCode Pix é estornado, transitando o status para <mark style="color:orange;">`StatusRefunded`</mark>.

Os webhooks são enviados em formato JSON e requerem um endpoint HTTPS público no lado do cliente para processamento. Cada webhook inclui um campo `event_name` para identificar o evento e um objeto `data` com detalhes específicos. A API realiza até **10 tentativas** de entrega do webhook, com intervalos exponenciais, até receber uma resposta `200 OK`.

**Especificações**:

* **Método**: <mark style="color:green;">`POST`</mark>
* **Content-Type**: `application/json`
* **URL**: Configurada no campo `notification_url` ao criar o QRCode.
* **Eventos**: <mark style="color:orange;">`qrcode.completed`</mark>, <mark style="color:orange;">`qrcode.refunded`</mark>.

### Configuração do Webhook

1. **Definir o** `notification_url`: Ao criar um QRCode via <mark style="color:green;">`POST`</mark>` ``/v1/pix` ou <mark style="color:green;">`POST`</mark>` ``/v1/pix/due`, inclua o campo `notification_url` (ex.: <https://your-webhook.com/notifications>) no corpo da requisição (veja [Criando um QRCode ](/integracao-com-a-api/meio-de-pagamento-pix/criando-um-qrcode-imediato)ou [Criando um QRCode com Vencimento](/integracao-com-a-api/meio-de-pagamento-pix/criando-um-qrcode-com-vencimento)).
2. **Implementar o endpoint**: Crie um endpoint HTTP <mark style="color:green;">`POST`</mark> no seu servidor para receber e processar os payloads JSON.
3. **Garantir HTTPS**: Use um certificado SSL válido para o `notification_url`.

### Estrutura dos Webhooks

#### Evento: qrcode.completed

Notifica quando um QRCode Pix é pago, indicando que o status mudou para <mark style="color:orange;">`StatusCompleted`</mark>.

**Payload**:

```json
{
  "event_name": "qrcode.completed",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "external_id": "ext-qr-12345",
    "transaction_id": "txn-789012",
    "e2e_id": "E123456789202401151030abcdef123456",
    "amount": 50.00,
    "payer": {
      "name": "João Silva",
      "document": "12345678901",
      "bank": {
        "code": "341",
        "name": "Banco Itaú",
        "agency": "1234",
        "account": "567890",
        "document": "12345678901"
      }
    },
    "description": "Payment for product or service"
  }
}
```

**Campos do Payload**:

| Campo                    | Tipo   | Descrição                                                       |
| ------------------------ | ------ | --------------------------------------------------------------- |
| event\_name              | string | Nome do evento (`qrcode.completed`).                            |
| data                     | object | Dados do evento.                                                |
| data.id                  | string | UUID do QRCode (ex.: 550e8400-e29b-41d4-a716-446655440000).     |
| data.external\_id        | string | Identificador externo do QRCode .                               |
| data.transaction\_id     | string | ID da transação Pix (ex.: txn-789012).                          |
| data.e2e\_id             | string | ID end-to-end do Pix (ex.: E123456789202401151030abcdef123456). |
| data.amount              | number | Valor pago em reais (ex.: 50.00).                               |
| data.payer               | object | Dados do pagador.                                               |
| data.payer.name          | string | Nome do pagador (ex.: João Silva).                              |
| data.payer.document      | string | CPF (11 dígitos) ou CNPJ (14 dígitos) do pagador.               |
| data.payer.bank          | object | Dados bancários do pagador.                                     |
| data.payer.bank.code     | string | Código do banco (ex.: 341 para Banco Itaú).                     |
| data.payer.bank.name     | string | Nome do banco (ex.: Banco Itaú).                                |
| data.payer.bank.agency   | string | Agência bancária (ex.: 1234).                                   |
| data.payer.bank.account  | string | Conta bancária (ex.: 567890).                                   |
| data.payer.bank.document | string | CPF ou CNPJ do titular da conta (ex.: 12345678901).             |
| data.description         | string | Descrição do pagamento (ex.: Payment for product or service).   |

#### Evento: qrcode.refunded

Notifica quando um QRCode Pix é estornado, indicando que o status mudou para StatusRefunded.

**Payload**:

```json
{
  "event_name": "qrcode.refunded",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "transaction_id": "txn-789012",
    "amount": 25.00,
    "client_code": "CUST-001",
    "description": "Refund requested by customer"
  }
}
```

**Campos do Payload**:

| Campo                | Tipo   | Descrição                                                             |
| -------------------- | ------ | --------------------------------------------------------------------- |
| event\_name          | string | Nome do evento (`qrcode.refunded`).                                   |
| data                 | object | Dados do evento.                                                      |
| data.id              | string | UUID do QRCode (ex.: 550e8400-e29b-41d4-a716-446655440000).           |
| data.transaction\_id | string | ID da transação Pix (ex.: txn-789012).                                |
| data.amount          | number | Valor estornado em reais (ex.: 25.00).                                |
| data.client\_code    | string | Identificador do cliente (ex.: CUST-001, equivalente a customer\_id). |
| data.description     | string | Descrição do estorno (ex.: Refund requested by customer).             |


# Consultando saldo

## Consultando o Saldo

A consulta de saldo na API do Pagou permite obter o saldo disponível do cliente associado à chave de API utilizada.

### Visão Geral Técnica

O endpoint <mark style="color:purple;">`GET`</mark>` ``/v1/customers/balance` retorna o saldo disponível do cliente em reais, identificado pela chave de API fornecida no cabeçalho `X-API-KEY`. A operação é síncrona, retornando `200 OK` com um corpo JSON contendo o campo balance.

**Especificações**:

* **Método**: GET
* **URL**:
  * Produção: `https://api.pagou.com.br/v1/customers/balance`
  * Sandbox: `https://sandbox-api.pagou.com.br/v1/customers/balance`
* **Autenticação**: Cabeçalho `X-API-KEY` com chave do painel.
* **Content-Type**: `application/json`
* **Resposta**: Status `200 OK` com corpo JSON contendo o saldo do cliente.
* **Erros**: `400 Bad Request`, `401 Unauthorized`, `404 Not Found`, `500 Internal Server Error`.

### Cabeçalhos

| Cabeçalho      | Valor                    | Descrição                                        |
| -------------- | ------------------------ | ------------------------------------------------ |
| `X-API-KEY`    | `sua_chave_api`          | Chave de autenticação.                           |
| `Content-Type` | `application/json`       | Formato JSON para a requisição.                  |
| `User-Agent`   | `NomeDaSuaAplicacao/1.0` | Identificador da aplicação (ex.: MinhaLoja/1.0). |

### Resposta

* **Status**: `200 OK`
* **Corpo**: JSON com o saldo disponível do cliente.

**Exemplo de Resposta**:

```json
{
  "balance": 1000.50
}
```

**Campos da Resposta**:

| Campo     | Tipo   | Descrição                                                             |
| --------- | ------ | --------------------------------------------------------------------- |
| `balance` | number | Saldo disponível do cliente em reais (ex.: 1000.50 para R$ 1.000,50). |

### Exemplos de Código

{% tabs %}
{% tab title="cURL" %}

```ruby
curl -X GET https://sandbox-api.pagou.com.br/v1/customers/balance \
  -H "X-API-KEY: sua_chave_api" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MinhaLoja/1.0"
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const fetch = require('node-fetch');

// Configuração
const url = 'https://sandbox-api.pagou.com.br/v1/customers/balance';
const headers = {
    'X-API-KEY': 'sua_chave_api',
    'Content-Type': 'application/json',
    'User-Agent': 'MinhaLoja/1.0'
};

fetch(url, {
    method: 'GET',
    headers: headers
})
    .then(response => {
        if (!response.ok) {
            return response.json().then(err => { throw new Error(`Erro ${response.status}: ${err.error.message}`); });
        }
        return response.json();
    })
    .then(data => {
        console.log(`Saldo disponível: R$ ${data.balance.toFixed(2)}`);
    })
    .catch(error => console.error('Erro na requisição:', error));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

# Configuração
url = "https://sandbox-api.pagou.com.br/v1/customers/balance"
headers = {
    "X-API-KEY": "sua_chave_api",
    "Content-Type": "application/json",
    "User-Agent": "MinhaLoja/1.0"
}

try:
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    data = response.json()
    print(f"Saldo disponível: R$ {data['balance']:.2f}")
except requests.RequestException as e:
    print(f"Erro na requisição: {e}")
    if e.response:
        print(f"Detalhes: {e.response.json()}")
```

{% endtab %}
{% endtabs %}

### Tratamento de Erros

| Código HTTP | Descrição             | Possível Causa                                     | Solução                                             |
| ----------- | --------------------- | -------------------------------------------------- | --------------------------------------------------- |
| 400         | Bad Request           | Requisição malformada (ex.: cabeçalhos inválidos). | Verificar formato dos cabeçalhos.                   |
| 401         | Unauthorized          | `X-API-KEY` inválido ou ausente.                   | Verificar chave.                                    |
| 500         | Internal Server Error | Erro interno da API.                               | Tentar novamente e contatar <contato@pagou.com.br>. |

**Exemplo de Resposta de Erro**:

```json
{
  "error": "Customer not found"
}
```

### Boas Práticas Técnicas

* **Segurança**: Armazene `X-API-KEY` em variáveis de ambiente e use HTTPS para todas as requisições.
* **Monitoramento**: Registre todas as requisições e respostas (incluindo o valor de balance e código de status HTTP) em logs para auditoria e depuração.
* **Testes no Sandbox**: Use <https://sandbox-api.pagou.com.br/v1/customers/balance> para simular consultas de saldo sem impacto em produção.


# Autenticação de Webhooks

Todos os webhooks enviados pela API do **Pagou**, incluindo eventos de boletos (ex.: <mark style="color:orange;">`charge.created`</mark>, <mark style="color:orange;">`charge.paid`</mark>) e Pix (ex.: <mark style="color:orange;">`qrcode.completed`</mark>, <mark style="color:orange;">`qrcode.refunded`</mark>), incluem os headers `X-Pagou-Signature` e `X-Pagou-Timestamp` para verificar a autenticidade e integridade das notificações. Esta seção detalha como validar esses headers, incluindo o processo de verificação da assinatura HMAC-SHA256 e do timestamp, exemplos de código em Python e JavaScript, e boas práticas para segurança.

### Visão Geral Técnica

Os webhooks da API do **Pagou** são enviados como requisições HTTP <mark style="color:green;">`POST`</mark> com corpo JSON para o `notification_url` configurado (ex.: <https://your-webhook.com/notifications>). Cada webhook inclui dois headers de autenticação:

* `X-Pagou-Signature`: Assinatura HMAC-SHA256 do conteúdo `timestamp + payload` (onde payload é a string JSON bruta do corpo da requisição). A assinatura é gerada com a chave de API do cliente.
* `X-Pagou-Timestamp`: Timestamp em segundos desde o epoch (ex.: 1754332106 para 2025-08-04 18:28:26).

### Validação dos Headers

Para garantir que o webhook é confiável, valide os headers X-Pagou-Signature e X-Pagou-Timestamp:

1. **Obter a chave de API**
2. **Validar** `X-Pagou-Signature`:
   * Extraia o `<hex>` do header `X-Pagou-Signature`.
   * Concatene o valor de `X-Pagou-Timestamp` com o payload JSON bruto (ex.: `1754329142` + `{"name":"charge.created",...}).`
   * Calcule o HMAC-SHA256 do resultado usando a chave de API.
   * Compare o hash calculado com o `<hex>` do header usando uma comparação resistente a ataques de tempo (ex.: `crypto.timingSafeEqual` em JavaScript, `hmac.compare_digest` em Python).
3. **Rejeitar se inválido**:
   * Retorne `401 Unauthorized` se a assinatura ou timestamp forem inválidos.
   * Registre tentativas inválidas para monitoramento.

**Nota**: A validação dos headers é altamente recomendada para segurança, mas os webhooks são enviados mesmo que a validação não seja implementada.

### Exemplos de Código

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const crypto = require('crypto');

function verifySignature(payload, timestamp, signature, secret) {
    const receivedDigest = signature;
    const message = timestamp + payload;
    const hmac = crypto.createHmac('sha256', secret);
    hmac.update(message);
    const computedDigest = hmac.digest('hex');
    
    try {
        const receivedBuffer = Buffer.from(receivedDigest, 'hex');
        const computedBuffer = Buffer.from(computedDigest, 'hex');
        
        if (receivedBuffer.length !== computedBuffer.length) {
            return false;
        }
        
        return crypto.timingSafeEqual(receivedBuffer, computedBuffer);
    } catch (e) {
        return false;
    }
}

// Example usage:
const payload = '{"name":"charge.created","data":{"id":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","transaction_id":"0","client_code":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","payload":{"transaction_id":"123","bank_emissor":"bradesco","bank_number":"137","bank_agency":"0001","bank_account":"12345678","bar_code":"123456789098765434321","line":"1234323465654758868986","bank_assignor":"Celcoin"}}}';
const timestamp = '1754329886'; // From X-Pagou-Timestamp header
const signature = 'ff502eeda47ceb3a6c0dc32a34d9503f32224f6fd8c9ad30a25c0f7cf0ca358c'; // From X-Pagou-Signature header
const apiKey = '07ab896a-d830-418b-8c55-47874dc6760e'; // API Key

const isValid = verifySignature(payload, timestamp, signature, apiKey);
console.log('Signature valid:', isValid);
```

### Boas Práticas Técnicas

* **Segurança**: Sempre valide `X-Pagou-Signature` e `X-Pagou-Timestamp` para garantir a origem e integridade do webhook.
* **Comparação Segura**: Use funções como `crypto.timingSafeEqual` (JavaScript) ou `hmac.compare_digest` (Python) para evitar ataques de tempo.
* **Prevenção de Replay Attacks**: Rejeite webhooks com `X-Pagou-Timestamp` fora de ±5 minutos do horário atual.
* **Monitoramento**: Registre `X-Pagou-Timestamp`, `X-Pagou-Signature`, e resultados da validação em logs para auditoria.
* **HTTPS**: Use um certificado SSL válido para o `notification_url`.
  {% endtab %}

{% tab title="Python" %}

```python
import hmac
import hashlib

def verify_signature(payload, timestamp, signature, secret):
    message = timestamp + payload
    computed_digest = hmac.new(
        key=secret.encode('utf-8'),
        msg=message.encode('utf-8'),
        digestmod=hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(computed_digest, signature)

# Example usage:
payload = '{"name":"charge.created","data":{"id":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","transaction_id":"0","client_code":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","payload":{"transaction_id":"123","bank_emissor":"bradesco","bank_number":"137","bank_agency":"0001","bank_account":"12345678","bar_code":"123456789098765434321","line":"1234323465654758868986","bank_assignor":"Celcoin"}}}'
timestamp = '1754329886'  # From X-Pagou-Timestamp header
signature = 'ff502eeda47ceb3a6c0dc32a34d9503f32224f6fd8c9ad30a25c0f7cf0ca358c'  # From X-Pagou-Signature header
api_key = '07ab896a-d830-418b-8c55-47874dc6760e'  # API Key

is_valid = verify_signature(payload, timestamp, signature, api_key)
print('Signature valid:', is_valid)
```

### Boas Práticas Técnicas

* **Segurança**: Sempre valide `X-Pagou-Signature` e `X-Pagou-Timestamp` para garantir a origem e integridade do webhook.
* **Comparação Segura**: Use funções como `crypto.timingSafeEqual` (JavaScript) ou `hmac.compare_digest` (Python) para evitar ataques de tempo.
* **Prevenção de Replay Attacks**: Rejeite webhooks com `X-Pagou-Timestamp` fora de ±5 minutos do horário atual.
* **Monitoramento**: Registre X-Pagou-Timestamp, X-Pagou-Signature, e resultados da validação em logs para auditoria.
* **HTTPS**: Use um certificado SSL válido para o notification\_url.
* **Testes**: Valide webhooks no ambiente sandbox (<https://sandbox.api.pagou.com.br/v1>) usando ferramentas como ngrok.
  {% endtab %}
  {% endtabs %}


