Nerva API Documentação
Integre pagamentos PIX na sua plataforma. Gere cobranças, acompanhe pagamentos em tempo real e gerencie saques com poucas linhas de código.
https://pixnerva.com.br/api1. Autenticação
Todas as requisições autenticadas devem incluir sua API Key no header x-api-key. A chave é gerada no painel do seller em Integrações > API Keys.
# Inclua em todas as requisições autenticadas
x-api-key: sk_live_a1b2c3d4e5f6g7h8i9j0...Segurança: Nunca exponha sua API Key no frontend ou em repositórios públicos. Use variáveis de ambiente no servidor.
2. Criar Cobrança PIX
Cria uma cobrança PIX instantânea. Retorna o código PIX “Copia e Cola” e o QR Code para o pagador. A cobrança expira em 24 horas por padrão (configurável via expirationInSeconds).
/salesParâmetros do Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| amount | number | SIM | Valor em reais (ex: 100.00). Mínimo R$ 0,01 / Máximo R$ 10.000,00 |
| customer | object | SIM | Dados do pagador (objeto aninhado — ver campos abaixo) |
| customer.document | string | SIM | CPF ou CNPJ do pagador (único campo obrigatório do customer) |
| customer.name | string | não | Nome completo do pagador |
| customer.email | string | não | Email do pagador |
| customer.phone | string | não | Telefone do pagador |
| description | string | não | Descrição da cobrança |
| items | array | não | Itens da cobrança [{description, quantity, unitPrice, tangible}] |
| expirationInSeconds | number | não | Expiração do PIX em segundos (300–86400, padrão: 86400) |
POST /sales
x-api-key: sk_live_...
Content-Type: application/json
{
"amount": 100.00,
"description": "Plano Premium",
"expirationInSeconds": 1800,
"customer": {
"name": "João Silva",
"document": "12345678901",
"email": "joao@email.com",
"phone": "11999999999"
},
"items": [
{ "description": "Plano Premium", "quantity": 1, "unitPrice": 100.00 }
]
}{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"amount": 100.00,
"fee": 8.98,
"netAmount": 91.02,
"pixCode": "00020101021226580014br.gov.bcb...",
"pixQrCode": "https://pixnerva.com.br/api/...",
"transactionId": "gw_tx_abc123"
}Cálculo das taxas: fee = (amount x 6.99%) + R$ 1.99 | netAmount = amount - fee
Exemplo: R$ 100,00 → fee = R$ 8,98 → netAmount = R$ 91,02
Idempotência
Para evitar cobranças duplicadas em caso de retentativa de rede ou timeout, envie o header idempotency-key ao criar uma cobrança. Se a chave já foi processada, a API devolve a resposta original (mesmo PIX, mesmo ID) sem criar nova cobrança.
Recomendado: use o ID interno do pedido no seu sistema (ex: order-12345) ou um UUID v4. A chave é válida por 24 horas — depois disso a mesma chave gera nova cobrança.
POST /sales
x-api-key: sk_live_...
idempotency-key: pedido-12345
Content-Type: application/json
{
"amount": 100.00,
"customer": { "document": "12345678901" }
}Importante: sempre que sua aplicação retentar uma criação de cobrança após um timeout, mande a MESMA idempotency-key. Sem ela, o seller pode acabar gerando 2 PIX cobrando o mesmo cliente.
Tracking de Marketing
Inclua o objeto tracking no body do POST /sales com UTMs, click IDs e cookies do pixel. Quando a venda for paga, a plataforma dispara automaticamente eventos para a Meta Conversions API e TikTok Events API (se a integração estiver ativa no painel do seller). Tudo opcional.
Campos do objeto tracking
| Campo | Descrição |
|---|---|
| utmSource | UTM Source (ex: facebook, google, tiktok) |
| utmMedium | UTM Medium (ex: cpc, social) |
| utmCampaign | UTM Campaign (nome da campanha) |
| utmContent | UTM Content (variação do criativo) |
| utmTerm | UTM Term (palavra-chave) |
| fbclid | Click ID do Facebook Ads (query param ?fbclid=...) |
| ttclid | Click ID do TikTok Ads |
| gclid | Click ID do Google Ads |
| fbp | Cookie _fbp do Facebook Pixel (browser id) |
| fbc | Cookie _fbc do Facebook Pixel (click id) |
| clientUserAgent | User-Agent do navegador do cliente final |
| clientIpAddress | IP do cliente final |
| eventId | Event ID para deduplicar pixel + CAPI (se vazio, derivamos do sale.id) |
{
"amount": 100.00,
"customer": { "document": "12345678901" },
"tracking": {
"utmSource": "facebook",
"utmCampaign": "black-friday-2026",
"fbclid": "IwAR2...",
"fbp": "fb.1.1700000000000.123456789",
"fbc": "fb.1.1700000000000.IwAR2...",
"clientUserAgent": "Mozilla/5.0 (...)",
"clientIpAddress": "201.10.20.30"
}
}Por quê: os browsers bloqueiam cada vez mais o Facebook Pixel, TikTok Pixel e Google Tag. Mandando esses dados pela API, a plataforma envia o evento server-to-server via Meta CAPI / TikTok Events API quando a venda for paga — recuperando atribuição de campanhas que o pixel sozinho perderia.
3. Consultar Cobrança
Retorna os detalhes completos de uma cobrança específica, incluindo o código PIX e o status do pagamento.
/sales/:idGET /sales/a1b2c3d4-e5f6-7890-abcd-ef1234567890 x-api-key: sk_live_...
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "paid",
"amount": 100.00,
"fee": 8.98,
"netAmount": 91.02,
"description": "Plano Premium",
"pixCode": "00020101021226580014br.gov.bcb...",
"pixQrCode": "https://pixnerva.com.br/api/...",
"payerName": "João Silva",
"payerEmail": "joao@email.com",
"payerDocument": "12345678901",
"payerPhone": "11999999999",
"paymentMethod": "PIX",
"transactionId": "gw_tx_abc123",
"createdAt": "2026-03-23T10: 00: 00Z",
"updatedAt": "2026-03-23T10: 05: 00Z"
}Status possíveis: pending → paid | failed | refunded | expired
4. Listar Cobranças
Retorna a lista paginada de cobranças da sua empresa, com filtros por status, data e busca.
/sales?page=1&limit=20&status=paidParâmetros de Query
| Parâmetro | Tipo | Descrição |
|---|---|---|
| page | number | Página (padrão: 1) |
| limit | number | Itens por página (padrão: 20) |
| status | string | Filtrar: pending, paid, failed, refunded, expired |
| startDate | string | Data inicial (ISO 8601) |
| endDate | string | Data final (ISO 8601) |
| search | string | Busca por nome, email ou documento |
{
"data": [
{
"id": "a1b2c3d4-...",
"status": "paid",
"amount": 100.00,
"fee": 8.98,
"netAmount": 91.02,
"payerName": "João Silva",
"paymentMethod": "PIX",
"createdAt": "2026-03-23T10: 00: 00Z"
}
],
"total": 142,
"page": 1,
"limit": 20
}5. Consultar Saldo
Retorna o saldo total, o valor retido (retenção de segurança) e o saldo disponível para saque.
/withdrawals/balanceGET /withdrawals/balance x-api-key: sk_live_...
{
"data": {
"available": 150000,
"withheld": 7500
}
}
// Valores em centavos (150000 = R$ 1.500,00)Retenção: 5% do valor líquido (netAmount) fica retido por 30 dias como proteção contra fraudes. Após o período, o valor é liberado automaticamente.
6. Solicitar Saque
Solicita um saque do saldo disponível. O saque passa por aprovação antes do processamento. Valor mínimo: R$ 10,00.
/withdrawalsParâmetros do Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| amount | number | SIM | Valor do saque em reais |
| method | string | SIM | "pix" |
| pixKeyType | string | SIM | Tipo (lowercase): cpf, cnpj, email, phone, random |
| pixKey | string | SIM | Chave PIX para receber o saque |
| reference | string | não | ID de referência no seu sistema (devolvido nos webhooks) |
POST /withdrawals
x-api-key: sk_live_...
Content-Type: application/json
{
"amount": 500.00,
"method": "pix",
"pixKeyType": "cpf",
"pixKey": "12345678901",
"reference": "pedido-saque-789"
}{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": 500.00,
"fee": 0,
"status": "pending",
"method": "pix",
"pixKeyType": "cpf",
"pixKey": "12345678901",
"reference": "pedido-saque-789",
"createdAt": "2026-03-23T14: 30: 00Z"
}Fluxo: pending → approved → processing → completed | rejected | failed
Listar Saques
Lista os saques da sua conta com filtros e paginação.
/withdrawals/my-withdrawalsQuery Parameters
| Campo | Tipo | Descrição |
|---|---|---|
| page | number | Página (default: 1) |
| limit | number | Itens por página (máx: 100) |
| status | string | Filtrar: pending, approved, processing, completed, rejected, failed |
GET /withdrawals/my-withdrawals?page=1&limit=20&status=completed x-api-key: sk_live_...
{
"data": [
{
"id": "a1b2c3d4-...",
"amount": 500.00,
"fee": 0,
"status": "completed",
"method": "pix",
"pixKey": "12345678901",
"reference": "pedido-saque-789",
"createdAt": "2026-03-23T14: 30: 00Z"
}
],
"total": 15,
"page": 1,
"limit": 20
}Buscar Saque por ID
Retorna os detalhes de um saque específico pelo ID.
/withdrawals/my-withdrawals/:idGET /withdrawals/my-withdrawals/a1b2c3d4-... x-api-key: sk_live_...
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": 500.00,
"fee": 0,
"status": "completed",
"method": "pix",
"pixKeyType": "cpf",
"pixKey": "12345678901",
"reference": "pedido-saque-789",
"createdAt": "2026-03-23T14: 30: 00Z",
"updatedAt": "2026-03-23T14: 35: 00Z"
}
}7. Webhooks
Configure uma URL de webhook no painel para receber notificações em tempo real quando o status de um pagamento mudar. A plataforma envia um POST com payload JSON assinado.
Headers enviados pela plataforma
| Header | Descrição |
|---|---|
| x-pixnerva-timestamp | Timestamp UNIX do momento do envio |
| x-pixnerva-signature | Assinatura HMAC-SHA256 do payload |
| Content-Type | application/json |
Eventos disponíveis
| Evento | Descrição |
|---|---|
| sale.pending | Cobrança criada, aguardando pagamento |
| sale.paid | Pagamento confirmado |
| sale.failed | Pagamento falhou |
| sale.expired | Cobrança expirou sem pagamento |
| sale.refunded | Pagamento estornado (total ou parcial) |
| sale.status_changed | Qualquer mudança de status (inclui previousStatus no payload) |
| sale.med_created | Contestação MED aberta |
| sale.med_accepted | Contestação aceita (estorno processado) |
| sale.med_rejected | Contestação rejeitada (favorável ao seller) |
| sale.med_cancelled | Contestação cancelada pelo cliente |
Payload de exemplo (sale.paid)
{
"event": "sale.paid",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "paid",
"amount": 100.00,
"fee": 8.98,
"netAmount": 91.02,
"payerName": "João Silva",
"payerEmail": "joao@email.com",
"payerDocument": "12345678901",
"paymentMethod": "PIX",
"transactionId": "gw_tx_abc123",
"createdAt": "2026-03-23T10: 00: 00Z",
"paidAt": "2026-03-23T10: 02: 30Z"
}
}Verificação de assinatura (HMAC-SHA256)
Para garantir que o webhook foi enviado pela plataforma e não foi adulterado, verifique a assinatura HMAC-SHA256 usando o secret do webhook.
- Extraia o
timestampe asignaturedos headers - Monte a string:
timestamp.body(timestamp + ponto + body raw) - Gere o HMAC-SHA256 usando seu
secret - Compare o resultado com a
signaturerecebida - Rejeite se o timestamp for maior que 5 minutos (proteção contra replay attack)
const crypto = require("crypto");
function verifyWebhook(req, secret) {
const timestamp = req.headers["x-pixnerva-timestamp"];
const signature = req.headers["x-pixnerva-signature"];
const body = JSON.stringify(req.body);
// Proteção contra replay attack (5 min)
const age = Date.now() / 1000 - Number(timestamp);
if (age > 300) return false;
// Gerar HMAC e comparar
const expected = crypto
.createHmac("sha256", secret)
.update(timestamp + "." + body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Retentativas: Se sua URL não responder com status 2xx, a plataforma reenvia automaticamente: 1 min → 5 min → 30 min (máximo 4 tentativas).
8. Códigos de Erro
A API retorna códigos HTTP padrão. Erros incluem um corpo JSON com message e statusCode.
| Status | Significado | Quando ocorre |
|---|---|---|
| 200 | Sucesso | Requisição processada com sucesso |
| 201 | Criado | Recurso criado com sucesso (venda, saque) |
| 400 | Dados inválidos | Campos obrigatórios ausentes ou formato incorreto |
| 401 | API Key inválida | Chave ausente, expirada ou revogada |
| 403 | Sem permissão | Empresa inativa ou sem acesso ao recurso |
| 404 | Não encontrado | Recurso não existe ou pertence a outro seller |
| 429 | Rate limit | Muitas requisições — aguarde e tente novamente |
| 500 | Erro interno | Falha no servidor — contate o suporte |
{
"message": "Saldo insuficiente para realizar o saque",
"statusCode": 400
}9. Exemplos de Código
Exemplos prontos para copiar e colar na sua integração. Substitua sk_live_... pela sua API Key real.
Criar cobrança PIX
curl -X POST https://pixnerva.com.br/api/sales \
-H "Content-Type: application/json" \
-H "x-api-key: sk_live_sua_chave_aqui" \
-d '{
"amount": 100.00,
"description": "Plano Premium",
"customer": {
"name": "João Silva",
"document": "12345678901",
"email": "joao@email.com",
"phone": "11999999999"
}
}'Consultar saldo
curl -X GET https://pixnerva.com.br/api/withdrawals/balance \ -H "x-api-key: sk_live_sua_chave_aqui"
Verificar assinatura do webhook
const crypto = require("crypto");
// Middleware Express para verificar webhook
function verifyWebhook(req, res, next) {
const secret = process.env.WEBHOOK_SECRET;
const timestamp = req.headers["x-pixnerva-timestamp"];
const signature = req.headers["x-pixnerva-signature"];
const body = JSON.stringify(req.body);
// Proteção contra replay (5 min)
const age = Date.now() / 1000 - Number(timestamp);
if (age > 300) {
return res.status(401).json({ error: "Timestamp expirado" });
}
const expected = crypto
.createHmac("sha256", secret)
.update(timestamp + "." + body)
.digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
if (!valid) {
return res.status(401).json({ error: "Assinatura inválida" });
}
next();
}
// Uso
app.post("/webhooks/payment", verifyWebhook, (req, res) => {
const { event, data } = req.body;
if (event === "sale.paid") {
console.log("Pagamento confirmado:", data.id);
// Liberar produto/serviço para o cliente
}
res.status(200).json({ received: true });
});