APIXdocs

Documentação para IAs

Todo o contrato da API em um único texto, pronto para colar no ChatGPT, Claude, Cursor ou Copilot e gerar a integração.

Como usar

Copie o texto abaixo e cole no seu assistente junto do que você quer fazer, por exemplo: "implemente o checkout PIX no meu Node.js usando esta API". Ele traz endpoints, exemplos, regras de valor e o fluxo de webhook.

Documento

Markdown

# APIX - API de Pagamentos: Documentação para Integração com IA

> Cole este documento no seu LLM (GPT, Claude, Cursor, Windsurf) para implementar a integração
> corretamente. Inclui todos os endpoints, webhooks, exemplos cURL e regras críticas.

---

## 1. VISÃO GERAL DO SISTEMA

- **Base URL:** `https://api.apix.tec.br`
- A plataforma oferece dois fluxos: **Checkout de Produto** e **Pagamento Direto (API Key)**.
- Os termos "payment", "transaction" e "transação" referem-se à mesma entidade.
- Pagamentos são **assíncronos** — a aprovação NÃO acontece na resposta do POST.
- Após criar o pagamento, consulte o status via **polling** ou receba via **webhook**.
- Todos os valores monetários estão em **centavos** (inteiro). Ex: R$ 99,90 = `9990`.

---

## 2. AUTENTICAÇÃO

### Rotas Públicas (sem autenticação)
```
GET  https://api.apix.tec.br/api/v1/products/:shortId/checkout
POST https://api.apix.tec.br/api/v1/payments
GET  https://api.apix.tec.br/api/v1/payments/:id/status
POST https://api.apix.tec.br/api/v1/products/:shortId/metrics/meta
```

### Rotas com API Key
```
POST https://api.apix.tec.br/api/v1/direct-payments
```

Header obrigatório:
```http
X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx
```

> ⚠️ Nunca exponha a API Key em código client-side (browser/app mobile).
> Use sempre em ambiente server-side.

### Alternativa: chave assinada (par de chaves secp256k1)

Mais segura que o `X-API-Key`: o vendedor gera o par, cadastra só a chave pública no dashboard
(Integrações & APIs → Nova chave → Par de chaves) e assina cada requisição com a chave privada.
Mesmo protocolo da MagenPay. Vale para todas as rotas com API Key. **Não envie `X-API-Key` junto** (400).

```bash
openssl ecparam -name secp256k1 -genkey -noout -out priv.pem   # privada: fica só no servidor
openssl ec -in priv.pem -pubout -out pub.pem                     # pública: cadastrar no dashboard
```

Headers obrigatórios:
```http
X-Public-Key-ID: apix_pk_xxxxxxxxxxxxxxxxxxxxxxxx
X-Timestamp: 2026-09-16T12:00:00.000Z        # ISO 8601 com fuso; até 5 min de diferença do servidor
X-Nonce: <16 a 128 caracteres [A-Za-z0-9._~+/=-], único por requisição>
X-Signature: <ECDSA secp256k1 + SHA-256, DER em base64>
```

**String assinada:** `JSON.stringify({ method, path, query, body, timestamp, nonce })` — sem espaços e
NESTA ordem de chaves. `method` em maiúsculas; `path` antes do `?`; `query` depois do `?` (`""` se não houver);
`body` = string exata enviada (`""` se não houver); `timestamp` e `nonce` = valores literais dos headers.

**Regras críticas:**
1. Envie o body **exatamente** como assinado — o servidor não reserializa. Serialize uma vez e reuse a string.
2. Nonce novo a cada requisição (repetido → 401 "Nonce já utilizado"), inclusive em retentativas.
3. Outras linguagens precisam gerar os mesmos bytes do `JSON.stringify`: PHP `json_encode` com
   `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`; Python `json.dumps(obj, separators=(",", ":"), ensure_ascii=False)`;
   Go `json.Encoder` com `SetEscapeHTML(false)` e sem o `\n` final.
4. O IP de origem precisa estar na lista cadastrada na chave (403 fora dela). A comparação é exata:
   se o servidor sai por IPv6, cadastre o endereço IPv6 (pode cadastrar IPv4 e IPv6 na mesma chave).

**Vetor de teste:** `POST /api/v1/direct-payments`, `X-Timestamp: 2026-09-16T12:00:00.000Z`,
`X-Nonce: b7Qm4rT9xK2pLw8vZs3nYa` e body
`{"amount":990,"description":"Pedido #123","paymentMethod":"pix","customer":{"name":"João Silva","email":"joao@exemplo.com","document":"12345678909"}}`
geram uma string cujo SHA-256 (UTF-8) é `9f3623e4ed27834921b88a1209d62300133e2faec6aa74a29007c2d0b920dbac`.

```javascript
import crypto from 'crypto';
import fs from 'fs';

const PUBLIC_KEY_ID = 'apix_pk_…';
const PRIVATE_KEY = fs.readFileSync('priv.pem', 'utf8');
const url = 'https://api.apix.tec.br/api/v1/direct-payments';
const body = JSON.stringify({ amount: 990, description: 'Pedido #123', paymentMethod: 'pix',
  customer: { name: 'João Silva', email: 'joao@exemplo.com', document: '12345678909' } });

const { pathname, search } = new URL(url);
const timestamp = new Date().toISOString();
const nonce = crypto.randomBytes(16).toString('base64url');
const signedData = JSON.stringify({ method: 'POST', path: pathname, query: search.slice(1), body, timestamp, nonce });
const signature = crypto.createSign('SHA256').update(signedData).sign(PRIVATE_KEY).toString('base64');

await fetch(url, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-Public-Key-ID': PUBLIC_KEY_ID,
    'X-Timestamp': timestamp, 'X-Nonce': nonce, 'X-Signature': signature },
  body, // exatamente a string assinada
});
```

---

## 3. FLUXO 1 — CHECKOUT DE PRODUTO

### Etapa 3.1 — Carregar Produto

```
GET https://api.apix.tec.br/api/v1/products/:shortId/checkout
Auth: Pública
```

**cURL:**
```bash
curl -X GET "https://api.apix.tec.br/api/v1/products/abc1234/checkout"
```

**JavaScript (fetch):**
```javascript
const res = await fetch("https://api.apix.tec.br/api/v1/products/abc1234/checkout");
const { data } = await res.json();
```

**Parâmetros:**
| Nome | Em | Tipo | Obrigatório | Descrição |
|------|----|------|-------------|-----------|
| shortId | path | string | Sim | Short ID do produto (7–12 chars) |
| affiliateId | query | string | Não | ID do afiliado para tracking |

**Resposta de sucesso (200):**
```json
{
  "hasError": false,
  "data": {
    "id": "uuid",
    "title": "Nome do Produto",
    "description": "Descrição do produto",
    "image": "https://cdn.exemplo.com/imagem.jpg",
    "currency": "BRL",
    "price": 9990,
    "sale_disabled": false,
    "allow_affiliate": true,
    "pixels": [
      {
        "type": "FACEBOOK",
        "content": "pixel-id",
        "active": true,
        "server_event": true,
        "purchase_event_pix": true,
        "purchase_event_bank_slip": false
      }
    ],
    "preferences": {
      "payment_method": ["PIX", "CREDIT_CARD"],
      "allow_payment_with_two_cards": false,
      "inputs_checkout": {
        "phone": true,
        "address": false,
        "birthdate": false
      },
      "orderbumps": []
    }
  }
}
```

**Regras:**
- Use `data.preferences.payment_method` para exibir apenas os métodos permitidos.
- Use `data.preferences.inputs_checkout` para decidir quais campos exibir no formulário.
- Se `data.sale_disabled === true`, bloquear a compra.

---

### Etapa 3.2 — Criar Pagamento (Checkout)

```
POST https://api.apix.tec.br/api/v1/payments
Content-Type: application/json
Auth: Pública
```

**cURL (PIX):**
```bash
curl -X POST "https://api.apix.tec.br/api/v1/payments" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentMethod": "pix",
    "productLink": "abc1234",
    "paymentValue": 9990,
    "customer": {
      "name": "João da Silva",
      "email": "joao@email.com",
      "document": "12345678901",
      "phone": "+5511999999999"
    }
  }'
```

**cURL (Cartão de Crédito):**
```bash
curl -X POST "https://api.apix.tec.br/api/v1/payments" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentMethod": "credit_card",
    "productLink": "abc1234",
    "paymentValue": 9990,
    "customer": {
      "name": "João da Silva",
      "email": "joao@email.com",
      "document": "12345678901"
    },
    "cardData": [
      {
        "cardNumber": "4111111111111111",
        "cardHolderName": "JOAO DA SILVA",
        "cardExpirationDate": "12/2028",
        "cardCvv": "123",
        "parcels": 3,
        "value": 9990
      }
    ]
  }'
```

**JavaScript (fetch - PIX):**
```javascript
const res = await fetch("https://api.apix.tec.br/api/v1/payments", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    paymentMethod: "pix",
    productLink: "abc1234",
    paymentValue: 9990,
    customer: {
      name: "João da Silva",
      email: "joao@email.com",
      document: "12345678901",
    },
  }),
});
const { data } = await res.json();
```

**Campos obrigatórios do body:**
| Campo | Tipo | Obrigatório | Descrição |
|-------|------|-------------|-----------|
| paymentMethod | "pix" | "credit_card" | "bank_slip" | Sim | Método de pagamento |
| productLink | string | Sim | Short ID do produto |
| paymentValue | number | Sim* | Valor em centavos (prioritário sobre productValue) |
| customer.name | string | Sim | Nome completo (3–128 chars) |
| customer.email | string | Sim | E-mail do comprador |
| customer.document | string | Sim | CPF (11 dígitos) ou CNPJ (14 dígitos), sem máscara |
| customer.phone | string | Não | Telefone no formato E.164 (+5511999999999) |
| customer.birthDate | string | Não | Formato DD/MM/YYYY |
| customer.address | object | Não | Endereço completo |
| customer.utm | object | Não | UTMs de rastreamento (source, medium, campaign, term, content, src, sck) |
| cardData | array | Condicional | Obrigatório se paymentMethod === "credit_card" |
| useTwoCards | boolean | Não | Dividir em dois cartões |
| additionalProducts | array | Não | Order bumps selecionados |
| affiliateId | string | Não | ID do afiliado |

**Regras de negócio:**
1. `paymentValue` é prioritário sobre `productValue` (campo legado).
2. Se `paymentMethod === "credit_card"`, `cardData` é obrigatório.
3. Se `useTwoCards === true`, `cardData` deve ter exatamente 2 objetos.
4. `customer.document` deve conter apenas dígitos.
5. `customer.birthDate` no formato `DD/MM/YYYY`.
6. Expiração do cartão no formato `MM/YYYY`.

**Resposta de sucesso (200):**
```json
{
  "hasError": false,
  "data": {
    "transaction_id": "uuid",
    "total_value": 9990,
    "status": "PENDING",
    "email": "joao@email.com",
    "product": { "id": "uuid", "title": "Nome do Produto" },
    "payment_method": "pix",
    "payment_data": {
      "payment_id": "uuid",
      "pix_key": "00020126...",
      "total_transaction_value": 9990,
      "expiration_date": "2024-01-15T10:30:00.000Z",
      "status": "pending",
      "status_detail": "waiting_payment"
    }
  }
}
```

---

### Etapa 3.3 — Consultar Status (Polling)

```
GET https://api.apix.tec.br/api/v1/payments/:id/status
Auth: Pública
```

**cURL:**
```bash
curl -X GET "https://api.apix.tec.br/api/v1/payments/uuid-da-transacao/status"
```

**JavaScript (fetch com polling):**
```javascript
const pollStatus = async (transactionId) => {
  const res = await fetch(
    `https://api.apix.tec.br/api/v1/payments/${transactionId}/status`
  );
  const { data } = await res.json();

  if (data.status === "PENDING") {
    setTimeout(() => pollStatus(transactionId), 15000); // 15s de intervalo
  } else if (data.status === "AUTHORIZED") {
    handleSuccess(data);
  } else {
    handleFailure(data.status); // REJECTED | FAILED
  }
};
```

**Resposta de sucesso (200):**
```json
{
  "hasError": false,
  "data": {
    "transaction_id": "uuid",
    "total_value": 9990,
    "status": "AUTHORIZED",
    "email": "joao@email.com",
    "product": { "id": "uuid", "title": "Nome do Produto" },
    "payment_method": "pix",
    "payment_data": { "status": "approved", "status_detail": "accredited" }
  }
}
```

---

## 4. FLUXO 2 — PAGAMENTO DIRETO (API KEY)

Ideal para integrações server-to-server sem produto cadastrado (e-commerces, SaaS, etc).

```
POST https://api.apix.tec.br/api/v1/direct-payments
X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
```

**cURL (PIX):**
```bash
curl -X POST "https://api.apix.tec.br/api/v1/direct-payments" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -d '{
    "amount": 9990,
    "description": "Curso de Marketing Digital",
    "paymentMethod": "pix",
    "customer": {
      "name": "João da Silva",
      "email": "joao@email.com",
      "document": "12345678901",
      "phone": "+5511999999999",
      "birthDate": "1990-01-15"
    }
  }'
```

**cURL (Cartão de Crédito):**
```bash
curl -X POST "https://api.apix.tec.br/api/v1/direct-payments" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -d '{
    "amount": 15000,
    "description": "Assinatura Premium Mensal",
    "paymentMethod": "credit_card",
    "customer": {
      "name": "Maria Souza",
      "email": "maria@email.com",
      "document": "12345678901"
    },
    "cardData": [
      {
        "cardNumber": "4111111111111111",
        "cardHolderName": "MARIA SOUZA",
        "cardExpirationDate": "12/28",
        "cardCvv": "123",
        "parcels": 1,
        "value": 15000
      }
    ]
  }'
```

**JavaScript (fetch - PIX):**
```javascript
const res = await fetch("https://api.apix.tec.br/api/v1/direct-payments", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "pk_live_xxxxxxxxxxxxxxxxxxxxxxxx",
  },
  body: JSON.stringify({
    amount: 9990,
    description: "Curso de Marketing Digital",
    paymentMethod: "pix",
    customer: { name: "João da Silva", email: "joao@email.com", document: "12345678901" },
  }),
});
const { data } = await res.json();
```

**Diferenças em relação ao Checkout de Produto:**
| Campo | POST /payments (Checkout) | POST /direct-payments (Direto) |
|-------|--------------------------|-------------------------------|
| Autenticação | Pública | API Key (X-API-Key) |
| Identificação do valor | paymentValue + productLink | amount + description |
| Produto vinculado | Sim | Não (product: null) |
| birthDate | DD/MM/YYYY | YYYY-MM-DD |
| Expiração cartão | MM/YYYY | MM/YY |
| Order bumps | additionalProducts[] | Não suportado |
| Afiliado | affiliateId | Não suportado |

**Regras:**
1. `amount` mínimo: `1` (em centavos).
2. `description` entre 3 e 255 caracteres.
3. Se `paymentMethod === "credit_card"`, `cardData` é obrigatório.
4. `customer.document` apenas dígitos.
5. `customer.birthDate` no formato `YYYY-MM-DD`.
6. Expiração do cartão no formato `MM/YY` (diferente do checkout).

**Resposta de sucesso (200):**
```json
{
  "hasError": false,
  "data": {
    "transaction_id": "uuid",
    "total_value": 9990,
    "status": "PENDING",
    "email": "joao@email.com",
    "product": null,
    "payment_method": "pix",
    "producer": { "name": "Nome do Vendedor", "email": "vendedor@email.com" },
    "payment_data": {
      "payment_id": "uuid",
      "pix_key": "00020126...",
      "total_transaction_value": 9990,
      "expiration_date": "2024-01-15T10:30:00.000Z",
      "status": "pending",
      "status_detail": "waiting_payment"
    }
  }
}
```

Após criar, use o mesmo endpoint de polling:
```bash
curl -X GET "https://api.apix.tec.br/api/v1/payments/uuid-da-transacao/status"
```

---

## 5. TABELA UNIFICADA DE STATUS

Esta tabela consolida todos os status possíveis de uma transação, eliminando qualquer ambiguidade.

| Status | Descrição | Final? | Aparece em polling? | Aparece em webhook? |
|--------|-----------|--------|---------------------|---------------------|
| `PENDING` | Aguardando pagamento ou processamento inicial | Não | Sim | Sim |
| `WAITING_PAYMENT` | Aguardando pagamento PIX ou boleto | Não | Sim | Sim |
| `IN_PROCESS` | Em processamento pelo gateway | Não | Sim | Sim |
| `AUTHORIZED` | Pagamento aprovado com sucesso | **Sim** | Sim | Sim |
| `REJECTED` | Pagamento recusado pelo processador | **Sim** | Sim | Sim |
| `FAILED` | Erro interno no processamento | **Sim** | Sim | Não |
| `REFUNDED` | Valor reembolsado ao comprador | **Sim** | Não | Sim |
| `CANCELLED` | Transação cancelada | **Sim** | Não | Sim |
| `CHARGED_BACK` | Contestação (chargeback) iniciada | **Sim** | Não | Sim |
| `CHARGEBACK` | Alias de CHARGED_BACK | **Sim** | Não | Sim |
| `IN_MEDIATION` | Disputa em processo de mediação | Não | Não | Sim |
| `IN_DISPUTE` | Alias de IN_MEDIATION | Não | Não | Sim |

**Regras para polling:**
- Pare o polling quando o status for final (`AUTHORIZED`, `REJECTED`, `FAILED`).
- Intervalo recomendado: **15 segundos**.
- `REFUNDED`, `CANCELLED`, `CHARGED_BACK` não aparecem em polling — chegam apenas via webhook.

**Regras para webhook:**
- `FAILED` não dispara webhook — detecte-o apenas via polling.
- Todos os outros status disparam pelo menos um webhook.

---

## 6. EVENTOS DE PIXEL META (SERVER-SIDE)

Para pixels com `server_event: true`, envie os eventos via API server-side:

```
POST https://api.apix.tec.br/api/v1/products/:shortId/metrics/meta
Content-Type: application/json
Auth: Pública
```

**cURL:**
```bash
curl -X POST "https://api.apix.tec.br/api/v1/products/abc1234/metrics/meta" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "eventName": "Purchase",
      "eventTime": 1706745600000,
      "eventSourceUrl": "https://checkout.exemplo.com/abc1234",
      "actionSource": "website",
      "userData": {
        "em": "joao@email.com",
        "ph": "+5511999999999",
        "fn": "João",
        "ln": "Silva",
        "country": "BR",
        "fbp": "fb.1.1706745600000.1234567890"
      }
    }
  }'
```

**JavaScript (fetch):**
```javascript
await fetch("https://api.apix.tec.br/api/v1/products/abc1234/metrics/meta", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    data: {
      eventName: "Purchase",
      eventTime: Date.now(),
      eventSourceUrl: window.location.href,
      actionSource: "website",
      userData: {
        em: "joao@email.com",
        ph: "+5511999999999",
        fn: "João",
        ln: "Silva",
        country: "BR",
        fbp: document.cookie.match(/_fbp=([^;]+)/)?.[1] || "",
      },
    },
  }),
});
```

**Mapeamento de eventos:**
| Momento | eventName |
|---------|-----------|
| Ao carregar o checkout | PageView |
| Ao iniciar preenchimento do formulário | InitiateCheckout |
| Ao selecionar produto ou order bump | AddToCart |
| Ao preencher dados de pagamento | AddPaymentInfo |
| Após POST /payments com resposta 2xx | Purchase |

**Regras:**
- O backend injeta automaticamente `client_ip_address` e `client_user_agent`.
- Deduplicação: cookie `pixel_event_{EVENT}_{shortId}` com 1 hora de validade.
- Se `test_event_code` está na URL, ignora deduplicação.

---

## 7. WEBHOOKS

### Como funciona
O sistema envia HTTP POST à URL configurada a cada mudança de status (evento `transaction.status_changed`).
Configure seus endpoints em /integracao (Integrações & APIs → Webhooks).

### Payload recebido
```json
{
  "transaction_id": "uuid",
  "total_value": 100000,
  "status": "AUTHORIZED",
  "product": { "id": "uuid", "title": "Nome do Produto" },
  "payment_method": "pix | credit_card | bank_slip",
  "producer": { "name": "Nome do Vendedor", "email": "suporte@vendedor.com" },
  "payment_data": {}
}
```

> Consulte a **Seção 5** para saber quais status disparam webhook e quais são finais.

### Política de retry
- **Tentativas:** 3
- **Intervalo:** 15 segundos fixo entre cada tentativa
- **Sucesso:** resposta HTTP 2xx do endpoint receptor

### Receptor completo (Node.js / Express)

```javascript
const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhooks/pixo', async (req, res) => {
  const { transaction_id, status, total_value, product, payment_method } = req.body;

  console.log(`[Webhook] ${transaction_id} → ${status}`);

  switch (status) {
    case 'AUTHORIZED':
      // Liberar acesso, enviar e-mail de confirmação, atualizar banco
      await fulfillOrder(transaction_id, product?.id);
      break;

    case 'REFUNDED':
      // Revogar acesso, processar reembolso interno, notificar cliente
      await revokeOrder(transaction_id);
      break;

    case 'CHARGED_BACK':
    case 'CHARGEBACK':
      // Revogar acesso, notificar equipe de risco
      await handleChargeback(transaction_id);
      break;

    case 'REJECTED':
    case 'CANCELLED':
      // Notificar cliente, oferecer nova tentativa
      await notifyFailure(transaction_id, status);
      break;

    case 'IN_MEDIATION':
    case 'IN_DISPUTE':
      // Registrar disputa, aguardar resolução
      await flagDispute(transaction_id);
      break;
  }

  // SEMPRE responder 2xx — sem isso o sistema tentará novamente
  res.status(200).json({ received: true });
});

app.listen(3000);
```

---

## 8. EXEMPLOS DE FLUXOS COMPLETOS

### Fluxo A — PIX via Checkout de Produto (end-to-end)

```bash
# 1. Carregar produto
curl -X GET "https://api.apix.tec.br/api/v1/products/abc1234/checkout"

# 2. Criar pagamento PIX
curl -X POST "https://api.apix.tec.br/api/v1/payments" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentMethod": "pix",
    "productLink": "abc1234",
    "paymentValue": 9990,
    "customer": { "name": "João da Silva", "email": "joao@email.com", "document": "12345678901" }
  }'

# 3. Polling de status (usar transaction_id da resposta anterior)
curl -X GET "https://api.apix.tec.br/api/v1/payments/uuid-da-transacao/status"
```

```javascript
// Fluxo completo em JavaScript
async function checkoutPix(productShortId, customer) {
  // 1. Carregar produto
  const productRes = await fetch("https://api.apix.tec.br/api/v1/products/" + productShortId + "/checkout");
  const { data: product } = await productRes.json();

  // 2. Criar pagamento
  const paymentRes = await fetch("https://api.apix.tec.br/api/v1/payments", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      paymentMethod: "pix",
      productLink: productShortId,
      paymentValue: product.price,
      customer,
    }),
  });
  const { data: payment } = await paymentRes.json();

  // 3. Exibir QR Code e iniciar polling
  renderQRCode(payment.payment_data.pix_key);

  const poll = async () => {
    const res = await fetch("https://api.apix.tec.br/api/v1/payments/" + payment.transaction_id + "/status");
    const { data } = await res.json();
    if (data.status === "PENDING") return setTimeout(poll, 15000);
    if (data.status === "AUTHORIZED") showSuccessPage();
    else showErrorPage(data.status);
  };
  poll();
}
```

---

### Fluxo B — Cartão de Crédito via Pagamento Direto (end-to-end)

```bash
# 1. Criar pagamento
curl -X POST "https://api.apix.tec.br/api/v1/direct-payments" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -d '{
    "amount": 9990,
    "description": "Acesso Premium - Mensal",
    "paymentMethod": "credit_card",
    "customer": { "name": "Maria Souza", "email": "maria@email.com", "document": "12345678901" },
    "cardData": [{
      "cardNumber": "4111111111111111",
      "cardHolderName": "MARIA SOUZA",
      "cardExpirationDate": "12/28",
      "cardCvv": "123",
      "parcels": 1,
      "value": 9990
    }]
  }'

# 2. Polling
curl -X GET "https://api.apix.tec.br/api/v1/payments/uuid-da-transacao/status"
```

---

### Fluxo C — Webhook + Liberação de Acesso (end-to-end)

```bash
# Simular webhook localmente com ngrok
ngrok http 3000
# Cadastrar a URL pública gerada em /integracao (Integrações & APIs → Webhooks)
```

```javascript
// Servidor receptor do webhook
app.post('/webhooks/pixo', async (req, res) => {
  const { transaction_id, status, product } = req.body;

  if (status === 'AUTHORIZED') {
    const order = await db.orders.findOne({ transaction_id });
    if (order) {
      await db.orders.update({ transaction_id }, { status: 'paid' });
      await sendConfirmationEmail(order.customer_email, product?.title);
      await grantAccess(order.user_id, product?.id);
    }
  }

  res.status(200).json({ received: true });
});
```

---

## 9. FORMATOS DE DADOS

| Campo | Formato | Exemplo |
|-------|---------|---------|
| CPF | 11 dígitos sem máscara | `12345678901` |
| CNPJ | 14 dígitos sem máscara | `12345678000190` |
| Telefone | E.164 | `+5511999999999` |
| CEP | 8 dígitos sem hífen | `01001000` |
| Valores monetários | Inteiro em centavos | `9990` = R$ 99,90 |
| Data nascimento (checkout) | DD/MM/YYYY | `15/01/1990` |
| Data nascimento (direct) | YYYY-MM-DD | `1990-01-15` |
| Expiração cartão (checkout) | MM/YYYY | `12/2028` |
| Expiração cartão (direct) | MM/YY | `12/28` |
| Datas ISO | ISO 8601 | `2024-01-15T10:30:00.000Z` |

---

## 10. FORMATO DE ERRO

Todas as respostas de erro seguem o padrão:
```json
{ "error": "Mensagem descritiva do erro" }
```

| HTTP Status | Situação |
|-------------|----------|
| 400 | Dados inválidos (falha de validação) |
| 401 | API Key ausente ou inválida |
| 404 | Recurso não encontrado |
| 422 | Regra de negócio violada |
| 500 | Erro interno do servidor |

---

## 11. REGRAS CRÍTICAS PARA O LLM

Ao gerar código de integração, siga SEMPRE estas regras:

1. **Valores em centavos:** Nunca envie `9.90`, sempre `990`.
2. **Polling obrigatório:** Nunca assuma aprovação síncrona após POST /payments.
3. **cardData condicional:** Inclua `cardData` apenas se `paymentMethod === "credit_card"`.
4. **Formato de documento:** Remova pontos, traços e barras antes de enviar.
5. **API Key server-side:** Nunca exponha `X-API-Key` no browser ou app mobile.
6. **Resposta 2xx em webhooks:** Responda 2xx mesmo que ocorra erro no processamento interno.
7. **Formato de data difere por fluxo:** `birthDate` e `cardExpirationDate` têm formatos diferentes entre checkout e pagamento direto.
8. **Polling interval:** 15 segundos entre consultas. Não faça polling com intervalo menor.
9. **Stop polling:** Pare quando o status for `AUTHORIZED`, `REJECTED` ou `FAILED`.
10. **FAILED não gera webhook:** Detecte o status `FAILED` apenas via polling — ele nunca chegará por webhook.