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.