# Mepagg API v1 - Referência técnica

> Manutenção interna: este arquivo deve permanecer sincronizado com `openapi.json`, `index.html`, `openapi.html` e `llms.txt`. Guia: `DOCUMENTATION_SYNC.md`.

## 1. Visão geral

- Base da API: `https://app.mepagg.com`
- Documentação da API: `https://documentacao.mepagg.com/`
- OpenAPI: `https://documentacao.mepagg.com/openapi.json`
- Autenticação: header `X-API-KEY`
- Formato principal: `application/json`

Esta versão da API pública da Mepagg é focada em operações transacionais. Ela permite integrar clientes, cobranças, recorrência, carnês, links de pagamentos, extrato, dashboard, SMS, e-mails enviados, dados cadastrais da conta e consultas de leitura sobre transferências.

A criação de transferências não faz parte da API pública e fica disponível somente no painel autenticado da Mepagg.

## 2. Regras de autenticação

Envie a chave da conta no header:

```http
X-API-KEY: SUA_CHAVE_DE_API
```

Exemplo:

```bash
curl "https://app.mepagg.com/api/v1/customers/" \
  -H "X-API-KEY: SUA_CHAVE_DE_API"
```

## 3. Regras funcionais importantes

- `boleto` e `pix` são formas de pagamento da cobrança.
- O tipo da fatura deve ser lido por `type_label` para exibição e `type_code` para regra de sistema.
- A origem da emissão deve ser lida por `issued_via_label` para exibição e `issued_via_code` para integrações.
- `issued_via`, `issued_via_code` e `issued_via_label` são campos de resposta e webhook, definidos internamente pela Mepagg; não envie esses campos no payload.
- O status da fatura deve ser lido por `status_label` para exibição e `status_code` para regra de sistema.
- Para clientes, enviar `document` com apenas números.
- Para SMS, o campo `content` aceita no máximo 160 caracteres.
- Em operações financeiras, a confirmação final deve considerar consulta posterior do recurso e, quando necessário, conciliação via extrato.
- Em operações críticas, envie `Idempotency-Key` para prevenir duplicidade acidental em retries do sistema da conta.

## 3.1 Idempotency-Key

Header suportado:

```http
Idempotency-Key: uuid-ou-chave-unica
```

Endpoints com suporte atual:

- `POST /api/v1/customers/`
- `PUT /api/v1/customers/{reference_id}/`
- `PATCH /api/v1/customers/{reference_id}/`
- `DELETE /api/v1/customers/{reference_id}/`
- `POST /api/v1/invoices/`
- `POST /api/v1/payment-links/`
- `POST /api/v1/invoices/{reference_id}/cancel/`
- `POST /api/v1/invoices/{reference_id}/refund/`
- `POST /api/v1/subscriptions/`
- `PUT /api/v1/subscriptions/{reference_id}/`
- `PATCH /api/v1/subscriptions/{reference_id}/`
- `DELETE /api/v1/subscriptions/{reference_id}/`
- `POST /api/v1/subscriptions/{reference_id}/status/`
- `POST /api/v1/sms/send/`

Regras:

- Repetindo a mesma chave com o mesmo payload, a API devolve a resposta original.
- Reutilizando a mesma chave com payload diferente, a API retorna conflito.
- O sistema da conta deve gerar uma chave única por operação lógica.

## 3.2 Catálogo canônico

Formas de pagamento da cobrança:

| Valor | Uso | Observação |
|---|---|---|
| `boleto` | Habilita pagamento por boleto bancário | Forma de pagamento da cobrança |
| `pix` | Habilita pagamento por PIX | Forma de pagamento da cobrança |

Tipos de desconto:

| Valor | Interpretação |
|---|---|
| `PERCENTAGE` | O campo `discount` representa percentual |
| `FIXED_VALUE` | O campo `discount` representa valor monetário em reais |

Leitura recomendada para faturas:

| Campo | Uso |
|---|---|
| `status_label` | Exibição em interface |
| `status_code` | Filtros, automações e regras |
| `type_label` | Exibição em interface |
| `type_code` | Regras e integrações |
| `type_display` | Alias atual de interface para o mesmo valor de `type_label` |
| `issued_via_label` | Exibição da origem da emissão |
| `issued_via_code` | Regras e integrações da origem da emissão |

Tipos de fatura expostos pela API e pelos webhooks:

| `type` | `type_code` | `type_label` |
|---|---|---|
| `2` | `subscription` | `Assinatura` |
| `3` | `oneoff` | `Avulsa` |
| `4` | `carne` | `Carnê` |
| `5` | `payment_link` | `Link de pagamento` |
| `6` | `payment_button` | `Botão de pagamento` |

Origem de emissão exposta pela API e pelos webhooks:

| `issued_via` | `issued_via_code` | `issued_via_label` |
|---|---|---|
| `PANEL` | `panel` | `Painel` |
| `API` | `api` | `API` |

Esses campos são somente leitura no contrato público. A origem é calculada internamente pela Mepagg conforme o canal real da emissão.

## 3.3 Limites operacionais

| Recurso | Limite / regra | Observação |
|---|---|---|
| Paginação | `limit` entre 1 e 200 | Aplicável às listagens principais |
| SMS | `content` com até 160 caracteres | Validar antes do envio |
| Boleto agenda | `inter_boleto_num_dias_agenda` entre 1 e 60 | Quando aplicável |
| Idempotência | `Idempotency-Key` com até 255 caracteres | Uma chave por operação lógica |

## 3.4 Rastreabilidade e correlação

- Persistir sempre `reference_id` dos recursos principais.
- Para faturas, guardar `status_code`, `type_code`, `issued_via_code`, `amount_paid` e `paid_at`.
- Para webhooks, guardar `X-Mepagg-Event-Id`, nome do evento, horário de recebimento e payload bruto.
- Para webhooks com replay protection, guardar também `X-Mepagg-Delivery-Id`, `X-Mepagg-Timestamp` e `X-Mepagg-Retry-Count`.
- Para conciliação financeira, relacionar o recurso transacional com o `related_reference_id` do extrato quando disponível.
- Em caso de divergência momentânea, tratar extrato e resumo financeiro como fonte final de verdade econômica.

## 3.5 Versionamento e compatibilidade

- A API pública atual opera sob `/api/v1/`.
- O sistema da conta deve ignorar campos desconhecidos sem quebrar parsing.
- Novos enums devem ser tratados de forma segura em interface e logs.
- Breaking changes devem ser acompanhadas pelo `changelog.html`.
- `openapi.json` permanece como contrato canônico para validação e geração de clientes.

## 4. Recursos disponíveis

### 4.1 Clientes

Rotas:

- `GET /api/v1/customers/`
- `POST /api/v1/customers/`
- `GET /api/v1/customers/{reference_id}/`
- `PUT /api/v1/customers/{reference_id}/`
- `PATCH /api/v1/customers/{reference_id}/`
- `DELETE /api/v1/customers/{reference_id}/`
- `GET /api/v1/customers/export/csv/`
- `GET /api/v1/customers/import/csv/model/`
- `POST /api/v1/customers/import/csv/preview/`
- `POST /api/v1/customers/import/csv/`

Campos principais de criação:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `name` | string | Sim | Nome ou razão social |
| `document` | string | Sim | CPF ou CNPJ com apenas números |
| `email_primary` | string | Não | E-mail principal |
| `email_secondary` | string | Não | E-mail alternativo |
| `phone_number` | string | Não | Celular/telefone com DDD |
| `street` | string | Sim | Logradouro |
| `neighborhood` | string | Sim | Bairro |
| `city` | string | Sim | Cidade |
| `state` | string | Sim | UF com 2 letras |
| `zipcode` | string | Sim | CEP com apenas números |
| `number` | string | Condicional | Obrigatório quando `no_number=false` |
| `no_number` | boolean | Não | Dispensa `number` quando `true` |
| `complement` | string | Não | Complemento |
| `observation` | string | Não | Observação interna |

Exemplo de criação:

```json
{
  "name": "Cliente Exemplo LTDA",
  "document": "12345678000195",
  "email_primary": "financeiro@clienteexemplo.com.br",
  "phone_number": "11987654321",
  "street": "Avenida Exemplo",
  "neighborhood": "Jardim Modelo",
  "number": "100",
  "zipcode": "01311000",
  "city": "Sao Paulo",
  "state": "SP"
}
```

### 4.2 Faturas

Rotas:

- `GET /api/v1/invoices/`
- `POST /api/v1/invoices/`
- `GET /api/v1/invoices/{reference_id}/`
- `POST /api/v1/invoices/{reference_id}/cancel/`
- `POST /api/v1/invoices/{reference_id}/refund/`
- `GET /api/v1/invoices/{reference_id}/second-copy/`
- `POST /api/v1/invoices/{reference_id}/resend-email/`
- `POST /api/v1/invoices/{reference_id}/resend-sms/`

Campos principais:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `customer_reference_id` | string | Sim* | Cliente da mesma conta |
| `customer_id` | integer | Sim* | Alternativa a `customer_reference_id` |
| `due_date` | string | Sim | Formato `YYYY-MM-DD` |
| `payment_methods` | array[string] | Sim* | `["boleto"]`, `["pix"]` ou `["boleto","pix"]` |
| `items` | array | Sim | Itens da cobrança. A fatura aceita um ou vários produtos/serviços, e o total é calculado pela soma dos itens |
| `fees` | number|string | Não | Juros |
| `fines` | number|string | Não | Multa |
| `discount_type` | string | Não | `PERCENTAGE` ou `FIXED_VALUE` |
| `discount` | number|string | Não | Percentual ou valor fixo |
| `inter_boleto_num_dias_agenda` | integer | Não | Entre 1 e 60 quando aplicável |

Estrutura dos itens:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `description` | string | Sim | Descrição do item |
| `qty` ou `quantity` | number|string | Sim | Quantidade positiva |
| `price` | number|string | Sim | Valor unitário não negativo |

Regras de total:

- A fatura pode ter um ou vários itens com descrições e valores diferentes.
- O `total_amount` retornado pela API corresponde à soma de `qty × price` de todos os itens antes dos ajustes financeiros.
- O valor mínimo total para criar uma fatura é `R$ 5,00`.

Campos recomendados de leitura:

| Campo | Uso |
|---|---|
| `reference_id` | Identificador externo da fatura |
| `status_label` | Exibir em interface |
| `status_code` | Regras, filtros e automações |
| `type_label` | Exibir em interface |
| `type_code` | Regras e integrações |
| `paid_at` | Data/hora de pagamento quando houver |
| `amount_paid` | Valor efetivamente pago quando houver |
| `public_url` | Link público da fatura para abrir o modelo Mepagg |
| `public_boleto_url` | Link público do boleto para impressão direta |
| `boleto.linha_digitavel` | Linha digitável para impressão própria |
| `boleto.codigo_barras` | Código de barras numérico do boleto |
| `boleto.nosso_numero` | Nosso número do boleto |
| `boleto.pdf_url` | PDF retornado pelo provedor bancário quando disponível |
| `pix.copia_e_cola` | Código Pix copia e cola quando disponível |

Modelo público e impressão própria:

- A fatura detalhada retorna `public_url` para abrir a cobrança pública da Mepagg.
- Quando houver boleto, a API também retorna `public_boleto_url` para abrir diretamente a visualização pública de impressão.
- O sistema da conta pode:
  - abrir e imprimir o modelo público da Mepagg;
  - ou montar seu próprio layout de boleto usando os campos estruturados da API.
- Em modelos próprios de boleto, incluir pelo menos: identificação do pagador, vencimento, valor, linha digitável, código de barras, nosso número, referência da cobrança e a intermediação `Mepagg LTDA - CNPJ 05.098.228/0001-80`.

Exemplo de criação:

```json
{
  "customer_reference_id": "CUST_EXAMPLE_001",
  "due_date": "2026-06-30",
  "payment_methods": ["boleto", "pix"],
  "discount_type": "FIXED_VALUE",
  "discount": "10.00",
  "items": [
    {
      "description": "Mensalidade da plataforma",
      "quantity": 1,
      "price": "120.00"
    }
  ]
}
```

Exemplo de resposta:

```json
{
  "success": true,
  "invoice": {
    "reference_id": "GLZOX8K19Q40NVLJ6WJ2PRYD7EV653",
    "status": 2,
    "status_code": "paid",
    "status_label": "Paga",
    "type": 3,
    "type_code": "oneoff",
    "type_label": "Avulsa",
    "type_display": "Avulsa",
    "payment_methods": ["boleto", "pix"],
    "due_date": "2026-06-15",
    "total": "5200.00",
    "amount_paid": "5200.00",
    "paid_at": "2026-06-15T10:18:00-03:00"
  }
}
```

### 4.3 Assinaturas

Rotas:

- `GET /api/v1/subscriptions/`
- `POST /api/v1/subscriptions/`
- `GET /api/v1/subscriptions/{reference_id}/`
- `POST /api/v1/subscriptions/{reference_id}/status/`

Tipos de recorrência aceitos em `interval`:

| Código | Rótulo retornado em `interval_label` | Uso |
|---|---|---|
| `WEEKLY` | `Semanal` | Repetição a cada 7 dias |
| `BIWEEKLY` | `Quinzenal` | Repetição a cada 15 dias |
| `MONTHLY` | `Mensal` | Repetição mensal |
| `BIMONTHLY` | `Bimestral` | Repetição a cada 2 meses |
| `QUARTERLY` | `Trimestral` | Repetição a cada 3 meses |
| `FOUR_MONTHS` | `Quadrimestral` | Repetição a cada 4 meses |
| `SEMIANNUAL` | `Semestral` | Repetição a cada 6 meses |
| `YEARLY` | `Anual` | Repetição anual |

Itens da assinatura:

- A assinatura aceita `items` com um ou vários produtos/serviços recorrentes.
- Cada item aceita `description`, `qty` ou `quantity` e `price`.
- O `total_amount` retornado pela API é a soma de todos os itens da assinatura.
- O valor mínimo total para criar uma assinatura é `R$ 5,00`.
- `POST`, `PUT`, `PATCH`, `DELETE` e `POST /api/v1/subscriptions/{reference_id}/status/` aceitam `Idempotency-Key`.

Estrutura dos itens da assinatura:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `description` | string | Sim | Descrição do produto ou serviço recorrente |
| `qty` ou `quantity` | number|string | Sim | Quantidade positiva |
| `price` | number|string | Sim | Valor unitário em reais |

### 4.4 Planos

Rotas:

- `GET /api/v1/subscription-plans/`
- `POST /api/v1/subscription-plans/`
- `GET /api/v1/subscription-plans/{reference_id}/`
- `PUT /api/v1/subscription-plans/{reference_id}/`
- `PATCH /api/v1/subscription-plans/{reference_id}/`
- `DELETE /api/v1/subscription-plans/{reference_id}/`

Campos principais:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `name` | string | Sim | Nome comercial do plano |
| `amount` | number|string | Sim | Valor do plano em reais |
| `interval` | string | Sim | Mesmos códigos de recorrência das assinaturas |
| `payment_method_ids` | array[integer] | Sim | IDs internos das formas de pagamento |
| `fees` | number|string | Não | Juros em valor monetário |
| `fines` | number|string | Não | Multa em valor monetário |
| `discount_type` | string | Não | `PERCENTAGE` ou `FIXED_VALUE` |
| `discount` | number|string | Não | Valor conforme `discount_type` |
| `inter_boleto_num_dias_agenda` | integer | Não | Entre `1` e `60` quando aplicável |
| `is_active` | boolean | Não | Estado operacional do plano |

Observações importantes:

- A listagem aceita `q`, `interval`, `limit` e `offset`.
- A resposta retorna `subscriptions_count` para indicar quantas assinaturas já usam o plano.
- `POST`, `PUT`, `PATCH` e `DELETE` aceitam `Idempotency-Key`.
- O plano não pode ser removido enquanto existir assinatura vinculada a ele.
- A criação, edição e remoção do plano disparam os webhooks `plan.created`, `plan.updated` e `plan.deleted`.

### 4.5 Carnês

Rotas:

- `GET /api/v1/carnes/`
- `POST /api/v1/carnes/`
- `GET /api/v1/carnes/{reference_id}/`
- `POST /api/v1/carnes/{reference_id}/cancel/`
- `POST /api/v1/carnes/{reference_id}/send-email/`

Observações importantes:

- `GET /api/v1/carnes/{reference_id}/` já retorna a visualização completa do carnê.
- O campo `carne.invoices` traz todas as parcelas do carnê como faturas, na mesma estrutura usada pela API de faturas.
- Use `summary` para leitura consolidada e `invoices` para montar a grade detalhada de parcelas.
- Cada parcela em `carne.invoices` possui sua própria `reference_id`, status, vencimento, itens e formas de pagamento.
- Para reproduzir a tela de detalhes do carnê, combine os dados do objeto `carne` com a lista completa de `invoices`.
- O campo `carne.public_url` abre a visualização pública do carnê com todas as parcelas.
- Cada parcela também expõe `public_url` e `public_boleto_url` quando aplicável.

Regras de criação com itens:

- O carnê pode ser criado com `items`, mas aceita apenas `1` produto/serviço nesse array.
- Esse item aceita `description`, `qty` ou `quantity` e `price`.
- Se `items` for enviado, a API calcula o `total_amount` a partir desse único item.
- Se `total_amount` também for enviado junto com `items`, ele deve ser igual à soma dos itens.
- A Mepagg distribui o valor total entre as parcelas do carnê, e cada parcela passa a ter seus próprios itens em `carne.invoices`.
- O valor mínimo total para criar um carnê é `R$ 5,00`.

Estrutura dos itens do carnê:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `description` | string | Sim | Descrição do produto ou serviço |
| `qty` ou `quantity` | number|string | Sim | Quantidade positiva |
| `price` | number|string | Sim | Valor unitário em reais |

Campos sugeridos para modelo próprio:

| Contexto | Campos sugeridos |
|---|---|
| Cabeçalho do carnê | `reference_id`, `description`, `installments_count`, `total_amount`, `first_due_date`, `customer.name`, `customer.document` |
| Resumo do carnê | `summary.status_label`, `summary.total_installments`, `summary.paid_installments`, `summary.open_installments` |
| Lista de parcelas | `invoices[].reference_id`, `invoices[].carne_installment_number`, `invoices[].due_date`, `invoices[].total_amount`, `invoices[].status_label`, `invoices[].payment_methods_display` |
| Dados de boleto por parcela | `invoices[].boleto.linha_digitavel`, `invoices[].boleto.codigo_barras`, `invoices[].boleto.nosso_numero`, `invoices[].boleto.pdf_url`, `invoices[].public_boleto_url` |
| Dados Pix por parcela | `invoices[].pix.copia_e_cola`, `invoices[].pix.txid`, `invoices[].public_url` |
| Identificação obrigatória da intermediação | `Mepagg LTDA - CNPJ 05.098.228/0001-80` |

Uso recomendado:

- Se quiser velocidade de implantação, use `carne.public_url` e os links públicos das parcelas.
- Se quiser personalizar layout, use a resposta de `GET /api/v1/carnes/{reference_id}/` para montar o próprio carnê e os próprios boletos.

### 4.6 Links de pagamentos

Rotas:

- `GET /api/v1/payment-links/`
- `POST /api/v1/payment-links/`
- `GET /api/v1/payment-links/{public_token}/`

Observações importantes:

- O link pode ser criado com valor fixo ou sem valor definido.
- Quando o link não tiver valor fixo, o pagador informa o valor na tela pública da Mepagg.
- O prazo do link é calculado com data e hora reais, então `due_at` é o campo principal para auditoria operacional.
- `due_option` controla a validade do próprio link.
- Quando `due_option=none`, o link fica sem vencimento e cada fatura gerada passa a usar a regra definida em `invoice_due_option`.
- Quando `due_option` tiver prazo (`today`, `1_day`, `5_days`, `10_days`, `15_days`, `30_days` ou `custom`), a fatura gerada herda essa mesma janela de vencimento do link.
- Links criados pelo painel autenticado da Mepagg ficam com origem `PANEL` / `panel` / `Painel`.
- O link criado pela API pública fica com origem `API`.
- Quando a tela pública desse link gerar uma fatura, ela sempre sairá com `type_code=payment_link`.
- Se o link original tiver sido criado pela API pública, essa fatura também sairá com `issued_via_code=api`; caso contrário, a origem da fatura permanece `panel`.

Campos principais:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `description` | string | Sim | Produto ou serviço exibido no checkout e copiado para a fatura gerada |
| `link_type` | string | Sim | `free` para link sem valor definido ou `fixed` para valor fixo |
| `amount` | number|string | Condicional | Obrigatório quando `link_type=fixed`; mínimo `5.00` |
| `due_option` | string | Sim | `today`, `1_day`, `5_days`, `10_days`, `15_days`, `30_days`, `custom` ou `none` |
| `custom_due_days` | integer | Condicional | Obrigatório quando `due_option=custom`; entre `1` e `29` |
| `invoice_due_option` | string | Condicional | Obrigatório quando `due_option=none`; aceita `today`, `1_day`, `5_days`, `10_days`, `15_days`, `20_days`, `30_days` ou `custom` |
| `invoice_custom_due_days` | integer | Condicional | Obrigatório quando `due_option=none` e `invoice_due_option=custom`; entre `1` e `29` |
| `usage_limit_mode` | string | Sim | `unlimited` ou `limited` |
| `usage_limit` | integer | Condicional | Obrigatório quando `usage_limit_mode=limited`; maior que `0` |
| `payment_methods` | array[string] | Sim* | Lista de slugs das formas de pagamento habilitadas |
| `payment_method_ids` | array[integer] | Sim* | Alternativa a `payment_methods`, usando IDs internos |
| `base_date` | string | Não | Data base opcional no formato `YYYY-MM-DD` |

`payment_methods` ou `payment_method_ids` são obrigatórios. Quando ambos forem enviados, a API prioriza a lista de slugs.

Status retornados:

| `status_code` | `status_label` | Quando aparece |
|---|---|---|
| `active` | `Ativo` | Link disponível para novas cobranças |
| `expired` | `Expirado` | Prazo do link já passou |
| `limit_reached` | `Limite atingido` | Quantidade máxima de usos já consumida |

Campos recomendados de leitura:

| Campo | Uso |
|---|---|
| `public_token` | Identificador público do link |
| `public_url` | URL pública do checkout |
| `status_code` | Regras, filtros e automações |
| `status_label` | Exibição em interface |
| `issued_via_code` | Origem estável do link para auditoria e integrações |
| `issued_via_label` | Exibição da origem do link |
| `due_at` | Data/hora final efetiva do link |
| `validity_display` | Texto pronto para mostrar a validade do link, inclusive `Sem vencimento` |
| `invoice_due_option_label` | Texto da regra de vencimento das faturas geradas; `today` aparece para humanos como `No mesmo dia` |
| `invoice_due_summary` | Resumo pronto da regra usada nas faturas geradas |
| `used_count` | Quantidade de cobranças já geradas |
| `remaining_uses` | Usos restantes quando houver limite |
| `usage_limit_display` | Texto pronto para interface |

Exemplo de criação:

```json
{
  "description": "Link sem vencimento para adesao",
  "link_type": "fixed",
  "amount": "249.90",
  "due_option": "none",
  "invoice_due_option": "20_days",
  "usage_limit_mode": "limited",
  "usage_limit": 3,
  "payment_methods": ["pix"]
}
```

Exemplo de resposta:

```json
{
  "success": true,
  "message": "Link de pagamento criado com sucesso.",
  "payment_link": {
    "public_token": "4dd78029-fb39-4c52-b0e6-2bc748d2832b",
    "status_code": "active",
    "status_label": "Ativo",
    "validity_display": "Sem vencimento",
    "invoice_due_option": "20_days",
    "invoice_due_option_label": "20 dias",
    "invoice_due_summary": "20 dias após a criação",
    "issued_via": "API",
    "issued_via_code": "api",
    "issued_via_label": "API",
    "public_url": "https://app.mepagg.com/link/4dd78029-fb39-4c52-b0e6-2bc748d2832b/"
  }
}
```

### 4.7 Transferências

Rotas públicas de leitura:

- `GET /api/v1/transfers/`
- `GET /api/v1/transfers/pricing/`
- `GET /api/v1/transfers/pix-keys/`
- `GET /api/v1/transfers/{reference_id}/`
- `GET /api/v1/transfers/{reference_id}/receipt/`

Regras:

- A criação de transferências não está disponível pela API pública.
- `POST /api/v1/transfers/` é exclusivo do painel autenticado da Mepagg.
- O motivo de recusa e o envio manual de recibo por e-mail também ficam restritos ao painel autenticado.
- A listagem e as consultas retornam somente transferências da própria conta autenticada.
- A conciliação final deve considerar detalhe da transferência e extrato.

### 4.8 Extrato, saldo e dashboard

Rotas:

- `GET /api/v1/statement/`
- `GET /api/v1/statement/summary/`
- `GET /api/v1/dashboard/overview/`
- `GET /api/v1/dashboard/widgets/`
- `GET /api/v1/dashboard/balances/`
- `GET /api/v1/dashboard/income-preview/`
- `GET /api/v1/dashboard/invoice-progress/`
- `GET /api/v1/dashboard/latest-invoices/`
- `GET /api/v1/dashboard/payment-method-chart/`
- `GET /api/v1/dashboard/invoice-type-chart/`
- `GET /api/v1/dashboard/received-calendar/`
- `GET /api/v1/dashboard/monthly-received-chart/`
- `GET /api/v1/dashboard/customers/`

Regras:

- O extrato é a fonte principal para conciliação financeira.
- O resumo financeiro consolida recebimentos, débitos, tarifas e saldo disponível.
- O dashboard é auxiliar para visão operacional e não substitui a conciliação do extrato.

### 4.9 SMS

Rotas:

- `POST /api/v1/sms/send/`
- `POST /api/v1/sms/buy-credits/`
- `GET /api/v1/sms/usages/`

Campos de envio:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `phone` | string | Sim | Celular com DDD |
| `content` | string | Sim | Limite máximo de 160 caracteres |

Campos da compra de créditos:

| Campo | Tipo | Obrigatório | Regra |
|---|---|---:|---|
| `sms_credit_package` | string | Sim | Código do pacote disponível para a conta. Exemplo: `500` ou `1000`. |
| `sms_purchase_method` | string | Sim | No momento, enviar `mepagg_balance`. |

Exemplo de compra de créditos:

```json
{
  "sms_credit_package": "500",
  "sms_purchase_method": "mepagg_balance"
}
```

Exemplo de resposta:

```json
{
  "success": true,
  "message": "Pacote de SMS comprado com sucesso.",
  "sms_credits": 1500
}
```

Exemplos por linguagem:

```bash
curl --request POST \
  --url 'https://app.mepagg.com/api/v1/sms/buy-credits/' \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: SUA_CHAVE_DE_API' \
  --data '{
    "sms_credit_package": "500",
    "sms_purchase_method": "mepagg_balance"
  }'
```

```js
import axios from 'axios';

const response = await axios.post(
  'https://app.mepagg.com/api/v1/sms/buy-credits/',
  {
    sms_credit_package: '500',
    sms_purchase_method: 'mepagg_balance',
  },
  {
    headers: {
      'Content-Type': 'application/json',
      'X-API-KEY': 'SUA_CHAVE_DE_API',
    },
    timeout: 30000,
  }
);

console.log(response.status);
console.log(response.data);
```

```python
import requests

response = requests.post(
    'https://app.mepagg.com/api/v1/sms/buy-credits/',
    headers={
        'Content-Type': 'application/json',
        'X-API-KEY': 'SUA_CHAVE_DE_API',
    },
    json={
        'sms_credit_package': '500',
        'sms_purchase_method': 'mepagg_balance',
    },
    timeout=30,
)

print(response.status_code)
print(response.json())
```

```php
<?php

$ch = curl_init('https://app.mepagg.com/api/v1/sms/buy-credits/');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-API-KEY: SUA_CHAVE_DE_API',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'sms_credit_package' => '500',
        'sms_purchase_method' => 'mepagg_balance',
    ]),
    CURLOPT_TIMEOUT => 30,
]);

$body = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo $httpCode . PHP_EOL;
echo $body . PHP_EOL;
```

Exemplos de erro:

```json
{
  "success": false,
  "message": "Pacote de SMS inválido."
}
```

```json
{
  "success": false,
  "message": "Chave de API inválida ou ausente."
}
```

Quando a compra é concluída, a Mepagg também pode enviar o webhook `sms.credits_purchased` com pacote adquirido, valor, método de compra e saldo final de créditos.

### 4.10 E-mails enviados

Rotas:

- `GET /api/v1/emails/dispatches/`

### 4.11 Dados cadastrais da conta

Rotas:

- `GET /api/v1/settings/account/`

Exemplo fictício de retorno:

```json
{
  "success": true,
  "account": {
    "name": "Empresa Exemplo de Cobrancas LTDA",
    "document": "12345678000199",
    "email": "financeiro@empresaexemplo.com.br",
    "phone_number": "1133334444",
    "municipal_registration": "15428",
    "municipality_name": "Belo Horizonte",
    "municipality_state": "MG"
  }
}
```

### 4.12 Webhooks

Os webhooks da Mepagg continuam disponíveis para consumo do sistema da conta, mas a gestão dos endpoints é feita no painel autenticado da Mepagg.

Headers de webhook:

| Header | Uso |
|---|---|
| `X-Mepagg-Event` | Nome do evento |
| `X-Mepagg-Event-Id` | Idempotência do evento |
| `X-Mepagg-Delivery-Id` | Identificador da tentativa de entrega |
| `X-Mepagg-Timestamp` | Unix timestamp usado na assinatura reforçada |
| `X-Mepagg-Retry-Count` | Contador de tentativas, começando em `0` |
| `X-Mepagg-Signature` | Assinatura HMAC SHA-256 legada sobre o payload bruto |
| `X-Mepagg-Signature-V2` | Assinatura HMAC SHA-256 com timestamp para reduzir replay |

Eventos importantes:

- `customer.created`
- `customer.updated`
- `customer.deleted`
- `invoice.created`
- `invoice.updated`
- `invoice.paid`
- `invoice.cancelled`
- `invoice.expired`
- `invoice.expired_final`
- `invoice.refunded`
- `subscription.created`
- `subscription.updated`
- `subscription.renewed`
- `plan.created`
- `plan.updated`
- `plan.deleted`
- `carne.cancelled`
- `payment_link.status_changed`
- `sms.credits_purchased`
- `sms.sent`
- `email.sent`

Observação sobre links de pagamentos:

- A API pública expõe o evento dedicado `payment_link.status_changed`.
- Esse webhook dispara quando o link muda de status, incluindo expiração por vencimento, desativação manual e limite de usos atingido.
- Use `data.status_code` para o estado atual (`active`, `expired`, `limit_reached`) e `data.status_reason_code` para o motivo estável (`active`, `manual_deactivated`, `due_date_expired`, `usage_limit_reached`).
- O snapshot completo do link vem em `data.payment_link`, incluindo `public_url`, `issued_via`, `payment_methods`, `status_reason_code` e `manual_deactivated_at`.
- Quando a cobrança nascer do checkout público de um link, acompanhe os eventos `invoice.created`, `invoice.paid`, `invoice.cancelled`, `invoice.expired` e `invoice.refunded`.
- Para identificar esse caso no webhook, leia `invoice.type_code=payment_link`.
- Para saber se o link original foi criado via painel ou API, leia também `invoice.issued_via_code`.

Headers enviados pela Mepagg:

```http
X-Mepagg-Event: invoice.paid
X-Mepagg-Event-Id: wh_evt_01JABCXYZ
X-Mepagg-Delivery-Id: 4832
X-Mepagg-Timestamp: 1712345678
X-Mepagg-Retry-Count: 0
X-Mepagg-Signature: sha256=HEX_DO_HMAC
X-Mepagg-Signature-V2: t=1712345678,sha256=HEX_DO_HMAC_V2
Content-Type: application/json
```

Validação recomendada:

- Preferir `X-Mepagg-Signature-V2`. Se necessário, ajuste a integração.
- Montar o material assinado como `${timestamp}.${payload_json_bruto}`.
- Validar a assinatura com HMAC SHA-256 usando o `signing_secret`.
- Rejeitar timestamps antigos ou muito no futuro, por exemplo fora de uma janela de 5 minutos.
- Persistir `X-Mepagg-Event-Id` como deduplicação lógica do evento.
- Persistir `X-Mepagg-Delivery-Id` para auditoria da tentativa e troubleshooting.

Exemplo em Node.js:

```js
import crypto from 'node:crypto';

function validateMepaggWebhookV2(rawBody, timestampHeader, signatureHeader, signingSecret) {
  const timestamp = String(timestampHeader || '').trim();
  const signature = String(signatureHeader || '').trim();
  const signedPayload = `${timestamp}.${rawBody}`;
  const digest = crypto
    .createHmac('sha256', signingSecret)
    .update(signedPayload, 'utf8')
    .digest('hex');
  const expected = `t=${timestamp},sha256=${digest}`;
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
```

Exemplo em Python:

```python
import hashlib
import hmac

def validate_mepagg_webhook_v2(raw_body, timestamp_header, signature_header, signing_secret):
    timestamp = str(timestamp_header or '').strip()
    signed_payload = f'{timestamp}.{raw_body}'
    digest = hmac.new(
        signing_secret.encode('utf-8'),
        signed_payload.encode('utf-8'),
        hashlib.sha256,
    ).hexdigest()
    expected = f't={timestamp},sha256={digest}'
    return hmac.compare_digest(signature_header.strip(), expected)
```

Exemplo de payload `customer.updated`:

```json
{
  "id": "wh_evt_01JCUSTXYZ",
  "type": "customer.updated",
  "occurred_at": "2026-06-17T18:42:11-03:00",
  "account": {
    "token": "ACC_EXAMPLE_001",
    "name": "Empresa Exemplo de Cobrancas LTDA",
    "document": "12345678000199"
  },
  "data": {
    "customer_id": 248,
    "customer_reference_id": "CST_EXAMPLE_248",
    "customer": {
      "id": 248,
      "reference_id": "CST_EXAMPLE_248",
      "name": "Cliente Exemplo LTDA",
      "document": "12345678000155",
      "email_primary": "financeiro@clienteexemplo.com.br",
      "email_secondary": "cobranca@clienteexemplo.com.br",
      "phone_number": "3133334444",
      "phone": "(31) 3333-4444",
      "state": "MG",
      "city": "Mariana",
      "street": "Rua Direita",
      "neighborhood": "Centro",
      "number": "120",
      "no_number": false,
      "complement": "Sala 03",
      "zipcode": "35420000",
      "formatted_address": "Rua Direita, 120, Centro, Mariana - MG, CEP 35420-000",
      "observation": "",
      "is_blocked": false,
      "blocked_reason": "",
      "is_defaulter": false,
      "is_deleted": false,
      "created_at": "2026-06-10T09:00:00-03:00",
      "updated_at": "2026-06-17T18:42:10-03:00",
      "deleted_at": null
    }
  }
}
```

Exemplo de payload `invoice.paid`:

Nos webhooks de fatura, use `type`, `type_code`, `type_label`, `issued_via`, `issued_via_code` e `issued_via_label`. Na API de consulta da fatura, `type_display` pode aparecer como alias de interface para `type_label`.

```json
{
  "id": "wh_evt_01JABCXYZ",
  "type": "invoice.paid",
  "occurred_at": "2026-06-15T10:19:12-03:00",
  "account": {
    "token": "ACC_EXAMPLE_001",
    "name": "Empresa Exemplo de Cobrancas LTDA",
    "document": "12345678000199"
  },
  "data": {
    "invoice_reference_id": "GLZOX8K19Q40NVLJ6WJ2PRYD7EV653",
    "amount_paid": "5200.00",
    "paid_at": "2026-06-15T10:18:00-03:00",
    "paid_source": "pix",
    "invoice": {
      "reference_id": "GLZOX8K19Q40NVLJ6WJ2PRYD7EV653",
      "status": 2,
      "status_label": "Paga",
      "status_code": "paid",
      "type": 3,
      "type_label": "Avulsa",
      "type_code": "oneoff",
      "issued_via": "API",
      "issued_via_code": "api",
      "issued_via_label": "API"
    }
  }
}
```

Exemplo de payload `carne.cancelled`:

```json
{
  "id": "wh_evt_01JCARXYZ",
  "type": "carne.cancelled",
  "occurred_at": "2026-06-17T19:15:00-03:00",
  "account": {
    "token": "ACC_EXAMPLE_001",
    "name": "Empresa Exemplo de Cobrancas LTDA",
    "document": "12345678000199"
  },
  "data": {
    "carne_reference_id": "CAR_01JABCXYZ",
    "cancelled_reason": "Solicitado pelo cliente.",
    "cancelled_installments": 3,
    "carne": {
      "reference_id": "CAR_01JABCXYZ",
      "description": "Parcelamento da adesão anual",
      "installments_count": 3,
      "total_amount": "120.00",
      "summary": {
        "status_code": "cancelled",
        "status_label": "Cancelado",
        "total_installments": 3,
        "paid_installments": 0,
        "cancelled_installments": 3,
        "open_installments": 0
      }
    }
  }
}
```

Exemplo de payload `sms.credits_purchased`:

```json
{
  "id": "wh_evt_01JSMSXYZ",
  "type": "sms.credits_purchased",
  "occurred_at": "2026-06-17T16:00:00-03:00",
  "account": {
    "token": "ACC_EXAMPLE_001",
    "name": "Empresa Exemplo de Cobrancas LTDA",
    "document": "12345678000199"
  },
  "data": {
    "sms_credit_purchase": {
      "package_code": "500",
      "credits_added": 500,
      "purchase_method": "mepagg_balance",
      "package_amount": "75.00",
      "sms_credits_balance": 1500,
      "source": "api"
    }
  }
}
```

Exemplo de validação da assinatura em Node.js:

```js
import crypto from 'node:crypto';

const rawBody = requestBodyBuffer;
const signature = request.headers['x-mepagg-signature'];
const expected = 'sha256=' + crypto
  .createHmac('sha256', process.env.MEPAGG_WEBHOOK_SECRET)
  .update(rawBody)
  .digest('hex');

if (signature !== expected) {
  throw new Error('Assinatura inválida');
}
```

Exemplo de validação da assinatura em PHP:

```php
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_MEPAGG_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, getenv('MEPAGG_WEBHOOK_SECRET'));

if (!hash_equals($expected, $signature)) {
    throw new RuntimeException('Assinatura inválida');
}
```

Boas práticas de webhook:

- Responder com HTTP `2xx` quando o evento for aceito.
- Preferir `X-Mepagg-Signature-V2` e validar a assinatura HMAC SHA-256.
- Processar o conteúdo com idempotência usando `event_id` e `delivery_id`.

## 5. Padrão de respostas

```json
{
  "success": true,
  "message": "Operação realizada com sucesso."
}
```

```json
{
  "success": false,
  "message": "Chave de API inválida."
}
```

## 6. Erros comuns

| HTTP | Mensagem / cenário | Causa | Solução |
|---|---|---|---|
| `400` | `Pacote de SMS inválido.`, `Informe um valor válido...` | Campo ausente, formato incorreto ou regra básica de validação rejeitada. | Validar payload no sistema da conta antes do envio. |
| `401` | `Chave de API inválida ou ausente.` | `X-API-KEY` ausente, incorreto ou de outra conta. | Enviar a chave correta no header e nunca no body. |
| `403` | `Você não possui saldo disponível...` | Saldo insuficiente, conta bloqueada ou operação não permitida. | Consultar saldo e status da conta antes da operação crítica. |
| `404` | `Fatura não encontrada.` | Recurso inexistente ou fora da conta autenticada. | Persistir e reutilizar `reference_id` corretamente. |
| `409` | `Conflito de idempotência`, `Saldo insuficiente` | Repetição incompatível, corrida de estado ou restrição operacional. | Usar `Idempotency-Key`, evitar retries cegos e reconsultar o recurso. |
| `422` | `Documento inválido.`, `E-mail inválido.` | Formato sintático aceito, mas rejeitado pela regra de negócio. | Normalizar documento, e-mail, CEP e chave Pix antes do POST. |
| `500` | `Erro interno ao processar a requisição.` | Falha inesperada, timeout interno ou indisponibilidade transitória. | Registrar logs, aplicar retry com backoff e reconsultar o estado final. |

Exemplo de tratamento:

```js
try {
  const response = await axios.post('https://app.mepagg.com/api/v1/sms/buy-credits/', payload, {
    headers: { 'X-API-KEY': 'SUA_CHAVE_DE_API' },
  });
  console.log(response.data);
} catch (error) {
  const status = error.response?.status;
  const body = error.response?.data;

  if (status === 400 || status === 422) {
    console.error('Validação rejeitada:', body);
  } else if (status === 401) {
    console.error('Falha de autenticação:', body);
  } else if (status === 403 || status === 409) {
    console.error('Regra de negócio bloqueou a operação:', body);
  } else {
    console.error('Erro inesperado, reconsulte o recurso antes de repetir:', body);
  }
}
```

## 7. Produção

- Guardar `reference_id` como identificador externo estável.
- Guardar `status_code` e `type_code` para automações.
- Usar `status_label` e `type_label` apenas para interface.
- Usar idempotência em webhooks.
- Nunca confiar só no POST inicial para confirmação financeira.
- Revalidar saldo disponível antes de transferências ou saques.
- Persistir `X-Mepagg-Event-Id` para impedir processamento duplicado de webhook.
- Registrar `paid_at`, `amount_paid`, `status_code` e `reference_id` no ERP ou sistema da conta.
