Autenticação
Gere suas credenciais no painel em Desenvolvedores > API Keys. Você receberá duas chaves:
| Chave | Formato | Uso | Permissões |
|---|---|---|---|
| Secret Key | sk_live_... |
Apenas no backend | Acesso total: criar, consultar, listar, configurar splits |
| Public Key | pk_live_... |
Frontend (browser) | Somente leitura: consultar e listar transações |
Envie a chave no header x-api-key em todas as requisições:
# Backend (Secret Key - acesso total)
curl -H "x-api-key: sk_live_sua_chave_secreta" \
https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/transactions
# Frontend (Public Key - somente consulta)
curl -H "x-api-key: pk_live_sua_chave_publica" \
https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/transactions/uuid
Erros e HTTP Codes
| Code | Significado | Quando ocorre |
|---|---|---|
| 200 | Sucesso | Requisição processada com sucesso |
| 400 | Bad Request | Dados inválidos ou campos obrigatórios ausentes |
| 401 | Unauthorized | API Key inválida, expirada ou ausente |
| 404 | Not Found | Transação ou recurso não encontrado |
| 429 | Rate Limited | Limite de 5 requisições/segundo excedido |
| 500 | Server Error | Erro interno (contate o suporte) |
Formato de Erro
{
"success": false,
"error": {
"message": "Valor mínimo: R$ 1,00 (100 centavos)",
"statusCode": 400
}
}
Status das Transações
| Status | Descrição |
|---|---|
| pending | Aguardando pagamento PIX (QR Code gerado) |
| processing | Pagamento em processamento pelo banco |
| paid | Pagamento confirmado — produto pode ser liberado |
| failed | Falha no pagamento |
| expired | QR Code expirou (30 minutos) |
| refunded | Valor devolvido ao cliente |
Criar Transação PIX
Cria uma cobrança PIX. Retorna o QR Code para o cliente pagar.
Headers
| Header | Tipo | Descrição | |
|---|---|---|---|
x-api-key |
string | obrigatório | Sua Secret Key (sk_live_...) |
x-idempotency-key |
string | opcional | Chave única para evitar cobranças duplicatas |
Body (JSON)
| Campo | Tipo | Descrição | |
|---|---|---|---|
amount |
integer | obrigatório | Valor em centavos. Ex: R$ 100,00 = 10000. Mínimo: 100 |
paymentMethod |
string | obrigatório | Método de pagamento: "pix" |
customer |
object | obrigatório | Dados do cliente (veja abaixo) |
customer.name |
string | obrigatório | Nome completo do cliente |
customer.email |
string | opcional | E-mail do cliente |
customer.phone |
string | opcional | Telefone com DDD |
customer.document |
object | opcional | { "type": "cpf", "number": "12345678900" } |
items |
array | opcional | [{ "title": "Produto", "unitPrice": 10000, "quantity": 1 }] |
split |
array | opcional novo | Split inline: [{ "email": "parceiro@email.com", "percentage": "10" }] |
postbackUrl |
string | opcional | URL HTTPS para webhook de confirmação |
externalId |
string | opcional | Seu ID interno para referência |
description |
string | opcional | Descrição da cobrança |
tracking |
object | opcional | UTMs do clique para atribuição de campanha na UTMify: { "utm_source", "utm_campaign", "utm_medium", "utm_content", "utm_term", "src", "sck" }. Se omitido, a venda é enviada à UTMify sem origem. |
Exemplo
curl -X POST https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/transactions \
-H "Content-Type: application/json" \
-H "x-api-key: sk_live_sua_chave_secreta" \
-d '{
"paymentMethod": "pix",
"amount": 10000,
"customer": {
"name": "João Silva",
"email": "joao@email.com",
"phone": "11999999999",
"document": { "type": "cpf", "number": "12345678900" }
},
"items": [
{ "title": "Assinatura Premium", "unitPrice": 10000, "quantity": 1 }
],
"postbackUrl": "https://meusite.com/webhook/velani",
"externalId": "pedido-123",
"tracking": {
"utm_source": "facebook",
"utm_campaign": "campanha-verao",
"utm_medium": "cpc",
"utm_content": "criativo-a"
}
}'
Resposta (200)
{
"success": true,
"data": {
"id": "uuid-da-transacao",
"status": "pending",
"amount": 10000,
"paymentMethod": "pix",
"customer": {
"name": "João Silva",
"email": "joao@email.com"
},
"pixQrCode": "00020126580014br.gov.bcb.pix...",
"pixQrCodeImage": "https://api.velanipagamentos.com.br/qrcode/xxx.png",
"expiresAt": "2026-01-15T11:00:00.000Z",
"createdAt": "2026-01-15T10:30:00.000Z"
},
"meta": {
"timestamp": "2026-01-15T10:30:00.000Z",
"version": "v1"
}
}
Consultar Transação
Consulta status e dados de uma transação. Aceita Secret Key ou Public Key.
curl https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/transactions/uuid \
-H "x-api-key: sk_live_sua_chave_secreta"
Resposta
{
"success": true,
"data": {
"id": "uuid-da-transacao",
"externalId": "pedido-123",
"status": "paid",
"amount": 10000,
"paymentMethod": "pix",
"customerName": "João Silva",
"customerEmail": "joao@email.com",
"paidAt": "2026-01-15T10:35:00.000Z",
"expiresAt": "2026-01-15T11:00:00.000Z",
"createdAt": "2026-01-15T10:30:00.000Z"
}
}
Listar Transações
Lista suas transações com paginação. Aceita Secret Key ou Public Key.
| Query Param | Tipo | Padrão | Descrição |
|---|---|---|---|
page | integer | 1 | Número da página |
limit | integer | 20 | Itens por página (máx: 100) |
Saques (Withdrawals) novo
A API de saques permite que sellers solicitem transferências PIX diretamente via API, sem precisar acessar o painel. Por padrão, os saques são criados como PENDING e processados após aprovação manual do administrador. Se o admin ativar a auto-aprovação de saque via API para a sua conta, o saque é processado e enviado na hora (veja abaixo).
1. Saque via API habilitado — precisa ser ativado pelo admin em Usuários > (seu usuário) > Ações > Saque via API
2. Destino do saque — configurar uma conta bancária cadastrada em Financeiro > Conta Bancária, OU enviar uma chave PIX externa diretamente na requisição (
pixKey, pixKeyType, holderName, holderDocument).3. CPF/CNPJ do titular — obrigatório em todo saque. As adquirentes validam o documento contra o dono da chave PIX. No modo PIX externo, envie
holderDocument. No modo conta bancária, cadastre o CPF/CNPJ no seu perfil (ou na conta bancária) — sem um documento válido a requisição é recusada com 400.4. IP na whitelist — o IP que faz a requisição deve estar cadastrado em Desenvolvedores > IPs Autorizados
Modo padrão — envie apenas
amount; o saque é direcionado para a conta bancária cadastrada do seller. O CPF/CNPJ do titular é obtido do cadastro (conta bancária ou perfil) e precisa estar preenchido e válido.Modo PIX externo — envie
amount + pixKey + pixKeyType + holderName + holderDocument; o saque é direcionado para a chave PIX informada (independente da conta bancária cadastrada). Funciona com todas as adquirentes configuradas na plataforma.
Quando o admin ativa Auto-aprovar saque para a sua conta (em Usuários > (seu usuário) > Ações > ↳ Auto-aprovar saque, logo abaixo de Saque via API), cada saque criado via
POST /v1/withdrawals é processado e enviado imediatamente, sem passar por aprovação manual — o retorno já vem com status: "PAID" ou "PROCESSING" (e o campo autoApproved: true). Requisitos: saque via API habilitado, senha de saque configurada na plataforma e CPF/CNPJ válido do titular. Se algum requisito faltar, o saque cai no fluxo normal e fica PENDING para aprovação manual. Sem esse recurso ativo, todo saque continua PENDING.
O campo
amount é exatamente o que você receberá. A taxa de saque é cobrada por cima do valor solicitado e debitada separadamente do saldo. Exemplo: se você solicitar R$ 50,00 e a taxa for R$ 2,00, serão debitados R$ 52,00 do saldo e você receberá R$ 50,00.
Status dos Saques
| Status | Descrição |
|---|---|
| PENDING | Aguardando aprovação do administrador |
| PROCESSING | Enviado à adquirente, aguardando confirmação (aparece na auto-aprovação) |
| PAID | Saque aprovado e PIX enviado para sua conta |
| REJECTED | Saque reprovado pelo admin (ver campo rejectionReason) |
| FAILED | Recusado pela adquirente — o valor é devolvido ao saldo automaticamente |
| UNDER_REVIEW | Envio sem confirmação (timeout) — em conferência; sem reenvio nem estorno até resolver |
Criar Saque
Solicita um saque. O valor solicitado + taxa é debitado imediatamente do saldo disponível. O saque fica como PENDING até aprovação manual pelo admin.
Headers
| Header | Tipo | Descrição | |
|---|---|---|---|
x-api-key |
string | obrigatório | Sua Secret Key (sk_live_...). Public Key não é aceita aqui. |
Content-Type |
string | obrigatório | application/json |
Body (JSON)
pixKey), envie no campo holderDocument abaixo. No modo conta bancária (só amount), o documento não vai no body mas precisa estar cadastrado e válido no seu perfil ou na conta bancária — sem ele o saque é recusado com 400. Os badges condicional abaixo se referem ao que vai no corpo da requisição, não à obrigatoriedade do documento em si.
| Campo | Tipo | Descrição | |
|---|---|---|---|
amount |
integer | obrigatório | Valor a receber em centavos. Ex: R$ 50,00 = 5000. Mínimo: 100 (R$ 1,00). Min/máx adicionais são definidos pela plataforma. |
pixKey |
string | opcional | Chave PIX de destino. Quando presente, ativa o modo PIX externo e os 3 campos abaixo passam a ser obrigatórios. Sem este campo, o saque vai para a conta bancária cadastrada do seller. |
pixKeyType |
enum | condicional | Obrigatório quando pixKey é enviado. Valores: CPF · CNPJ · EMAIL · PHONE · RANDOM |
holderName |
string | condicional | Nome completo do titular da chave PIX. Obrigatório quando pixKey é enviado. Apenas letras, espaços e pontuação simples (. , - '). Mín. 3, máx. 120 caracteres. |
holderDocument |
string | condicional | CPF (11 dígitos) ou CNPJ (14 dígitos) do titular, somente números. Obrigatório quando pixKey é enviado. No modo conta bancária (sem pixKey) o documento não vai no body, mas precisa estar cadastrado e válido no seu perfil ou na conta bancária — o saque é recusado se não houver. |
postbackUrl |
string | opcional | URL HTTPS que recebe o webhook deste saque (withdrawal.paid / withdrawal.rejected). Se ausente, o webhook vai para os endpoints configurados em Desenvolvedores > Webhooks que escutam esses eventos. |
externalReference |
string | opcional | Chave de idempotência (recomendado; pode também ser enviada no header x-idempotency-key). 6–64 caracteres: letras, números, hífen, underscore. Única por conta. Retry com a mesma chave retorna o MESMO saque (campo idempotentReplay: true na resposta) em vez de criar — e debitar — outro. Use sempre que sua integração tiver retry automático/timeout. |
Validação de pixKey por tipo
| pixKeyType | Formato exigido | Exemplo |
|---|---|---|
CPF | Exatamente 11 dígitos. Validado com algoritmo de dígitos verificadores. | "12345678909" |
CNPJ | Exatamente 14 dígitos. Validado com algoritmo de dígitos verificadores. | "12345678000190" |
EMAIL | E-mail válido, máx. 100 caracteres. Convertido para minúsculas. | "joao@email.com" |
PHONE | 10 a 13 dígitos. Números BR sem código de país recebem prefixo +55 automaticamente. | "+5511999998888" |
RANDOM | UUID v4 — 32 hex sem hífens, ou 36 chars no formato 8-4-4-4-12. | "550e8400-e29b-41d4-a716-446655440000" |
Exemplo 1 — Saque para conta bancária cadastrada
curl -X POST https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/withdrawals \
-H "Content-Type: application/json" \
-H "x-api-key: sk_live_sua_chave_secreta" \
-d '{ "amount": 5000 }'
Exemplo 2 — Saque para chave PIX externa
curl -X POST https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/withdrawals \
-H "Content-Type: application/json" \
-H "x-api-key: sk_live_sua_chave_secreta" \
-d '{
"amount": 5000,
"pixKey": "joao@email.com",
"pixKeyType": "EMAIL",
"holderName": "João da Silva",
"holderDocument": "12345678909"
}'
Resposta (200) — Modo padrão (conta bancária)
{
"success": true,
"data": {
"id": "uuid-do-saque",
"amount": 50.00,
"fee": 2.00,
"netAmount": 48.00,
"status": "PENDING",
"destination": "BANK_ACCOUNT",
"pixKey": null,
"pixKeyType": null,
"holderName": null,
"holderDocument": null,
"createdAt": "2026-05-04T12:00:00.000Z",
"updatedAt": "2026-05-04T12:00:00.000Z",
"paidAt": null,
"rejectionReason": null,
"autoApproved": false
}
}
/* amount = total debitado do saldo (bruto solicitado)
fee = taxa da plataforma cobrada
netAmount = valor líquido que será creditado no PIX (amount − fee)
autoApproved = true quando a auto-aprovação processou o saque na hora (status vem "PAID"/"PROCESSING") */
Resposta (200) — Modo PIX externo
{
"success": true,
"data": {
"id": "uuid-do-saque",
"amount": 50.00,
"fee": 2.00,
"netAmount": 48.00,
"status": "PENDING",
"destination": "EXTERNAL_PIX",
"pixKey": "joao@email.com",
"pixKeyType": "EMAIL",
"holderName": "João da Silva",
"holderDocument": "12345678909",
"createdAt": "2026-05-04T12:00:00.000Z",
"updatedAt": "2026-05-04T12:00:00.000Z",
"paidAt": null,
"rejectionReason": null,
"autoApproved": false
}
}
"status": "PAID" (ou "PROCESSING" enquanto a adquirente confirma) e "autoApproved": true, com paidAt preenchido. Nenhuma ação manual é necessária. Se a adquirente recusar, o status volta "FAILED" e o valor é devolvido ao saldo automaticamente.
401 Unauthorized. Você pode adicionar até 10 IPs por conta.
pixKey, holderName e holderDocument são validados contra:
- caracteres de controle (newline, null byte, tab) — bloqueia log forging;
- caracteres invisíveis (zero-width, RTL/LTR override, BOM) — bloqueia homoglyph attacks;
- tags HTML (
<,>) e padrões script-like (javascript:,vbscript:,data:,<script>,on*=); - backticks e template literals (
`,${}); - tamanhos máximos:
pixKey140,holderName120,holderDocument18.
400 Bad Request com mensagem específica.
Erros comuns
| HTTP | Mensagem | Causa |
|---|---|---|
| 400 | É necessário um CPF/CNPJ válido do titular para saque via API... | Modo conta bancária sem CPF/CNPJ válido no perfil nem na conta bancária. Cadastre o documento ou use o modo PIX externo com holderDocument. |
| 400 | Para saque em chave PIX externa, os campos são obrigatórios: pixKeyType, holderName... | Você enviou pixKey mas faltou algum dos demais campos do holder. |
| 400 | pixKey do tipo CPF deve conter exatamente 11 dígitos | Formato da chave PIX não bate com o pixKeyType declarado. |
| 400 | CPF/CNPJ informado em holderDocument é inválido | Documento falhou na validação de dígitos verificadores. |
| 400 | Nome do titular inválido | O holderName contém caracteres fora da whitelist (números, símbolos, etc.). |
| 400 | Campo X contém caracteres de controle não permitidos | Algum campo trouxe newline, null byte ou outro caractere de controle. |
| 400 | Saldo insuficiente | Saldo disponível menor que amount. |
| 401 | IP não autorizado para esta conta | Adicione o IP em Desenvolvedores > IPs Autorizados. |
| 403 | Saque via API não está habilitado | Pedir ao admin para habilitar em Usuários > (seu usuário) > Ações > Saque via API. |
Listar Saques
Lista todos os saques da conta com paginação. Aceita Secret Key ou Public Key.
| Query Param | Tipo | Padrão | Descrição |
|---|---|---|---|
page | integer | 1 | Número da página |
limit | integer | 20 | Itens por página (máx: 100) |
curl "https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/withdrawals?page=1&limit=20" \
-H "x-api-key: sk_live_sua_chave_secreta"
Resposta (200)
{
"success": true,
"data": [
{
"id": "uuid-do-saque",
"amount": 52.00,
"fee": 2.00,
"netAmount": 50.00,
"status": "PENDING",
"createdAt": "2026-04-13T12:00:00.000Z",
"paidAt": null,
"rejectionReason": null
}
],
"meta": {
"total": 5,
"page": 1,
"limit": 20
}
}
Consultar Saque
Consulta detalhes de um saque específico. Aceita Secret Key ou Public Key.
curl "https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/withdrawals/uuid-do-saque" \
-H "x-api-key: sk_live_sua_chave_secreta"
Resposta (200)
{
"success": true,
"data": {
"id": "uuid-do-saque",
"amount": 52.00,
"fee": 2.00,
"netAmount": 50.00,
"status": "PAID",
"createdAt": "2026-04-13T12:00:00.000Z",
"updatedAt": "2026-04-13T14:30:00.000Z",
"paidAt": "2026-04-13T14:30:00.000Z",
"rejectionReason": null
}
}
Split de Pagamento novo
O Split de Pagamento permite dividir automaticamente o valor de cada venda com parceiros, afiliados ou sócios. Ao criar uma transação, envie o campo split com os destinatários e porcentagens. Quando o pagamento é confirmado, os valores são creditados automaticamente.
1. Ao criar a transação, envie o campo
split com e-mail e porcentagem de cada destinatário2. O cliente paga normalmente via PIX
3. Após a taxa da plataforma, o valor líquido é dividido automaticamente
4. Parceiro recebe sua porcentagem e você recebe o restante — tudo automático
Split na Transação
Envie o campo split ao criar uma transação para dividir o valor automaticamente:
Exemplo com Split Inline
curl -X POST https://api.velanipagamentos.com.br/api/v1/api-gateway/v1/transactions \
-H "Content-Type: application/json" \
-H "x-api-key: sk_live_sua_chave_secreta" \
-d '{
"paymentMethod": "pix",
"amount": 10000,
"customer": {
"name": "João Silva",
"email": "joao@email.com"
},
"split": [
{ "email": "parceiro@email.com", "percentage": "10" },
{ "email": "afiliado@email.com", "percentage": "5" }
],
"postbackUrl": "https://meusite.com/webhook",
"externalId": "pedido-456"
}'
Campos do Split
| Campo | Tipo | Descrição | |
|---|---|---|---|
split[].email |
string | obrigatório | E-mail do destinatário (deve ter conta na plataforma) |
split[].percentage |
string | obrigatório | Porcentagem do valor líquido. Ex: "10" = 10% |
Exemplo de divisão:
Venda: R$ 100,00
Taxa plataforma (6%): - R$ 6,00
Valor líquido: R$ 94,00
Split parceiro (10%): R$ 9,40 → creditado para parceiro@email.com
Split afiliado (5%): R$ 4,70 → creditado para afiliado@email.com
Você recebe (85%): R$ 79,90
Webhooks
Receba notificações em tempo real quando transações mudam de status. Configure via painel (Desenvolvedores > Webhooks) ou envie postbackUrl na transação.
Payload do Webhook
{
"event": "transaction.paid",
"timestamp": "2026-01-15T10:35:00.000Z",
"data": {
"id": "uuid-da-transacao",
"externalId": "pedido-123",
"amount": 10000,
"status": "paid",
"paymentMethod": "pix",
"customerName": "João Silva",
"paidAt": "2026-01-15T10:35:00.000Z"
},
"signature": "hmac-sha256-do-payload",
"version": "1.0",
"source": "velani-gateway"
}
Eventos disponíveis
| Evento | Categoria | Descrição |
|---|---|---|
transaction.paid | PIX | Pagamento PIX confirmado |
transaction.created | PIX | Cobrança PIX criada |
transaction.failed | PIX | Transação falhou ou expirou |
transaction.refunded | PIX | Transação reembolsada |
withdrawal.paid | Saque | Saque aprovado e PIX enviado para sua conta |
withdrawal.rejected | Saque | Saque reprovado pelo administrador |
Payload — withdrawal.paid / withdrawal.rejected
{
"event": "withdrawal.paid",
"timestamp": "2026-04-13T14:30:00.000Z",
"data": {
"id": "uuid-do-saque",
"amount": 52.00,
"fee": 2.00,
"netAmount": 50.00,
"status": "PAID",
"paidAt": "2026-04-13T14:30:00.000Z",
"rejectionReason": null,
"createdAt": "2026-04-13T12:00:00.000Z",
"updatedAt": "2026-04-13T14:30:00.000Z"
},
"signature": "hmac-sha256-do-payload",
"version": "1.0",
"source": "velani-gateway"
}
/* Para withdrawal.rejected:
"event": "withdrawal.rejected",
"data.status": "REJECTED",
"data.paidAt": null,
"data.rejectionReason": "Dados bancários inválidos" */
Validação de Assinatura (HMAC-SHA256)
const crypto = require('crypto');
function validateWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload.data))
.digest('hex');
return expected === signature;
}
// Express.js
app.post('/webhook/velani', (req, res) => {
const { event, data, signature } = req.body;
if (!validateWebhook(req.body, signature, 'whsec_seu_secret')) {
return res.status(401).json({ error: 'Invalid signature' });
}
if (event === 'transaction.paid') {
// Pagamento confirmado! Liberar produto.
console.log(`Pago: ${data.id} - R$ ${(data.amount/100).toFixed(2)}`);
}
res.status(200).json({ received: true });
});
Exemplo Completo
Fluxo de integração ponta a ponta com Node.js + Express:
1. Criar cobrança PIX (com split)
const axios = require('axios');
const API_KEY = 'sk_live_sua_chave_secreta';
const BASE_URL = 'https://api.velanipagamentos.com.br/api/v1/api-gateway';
app.post('/criar-pagamento', async (req, res) => {
const { nome, email, valor } = req.body;
const { data } = await axios.post(`${BASE_URL}/v1/transactions`, {
paymentMethod: 'pix',
amount: Math.round(valor * 100),
customer: { name: nome, email },
items: [{ title: 'Meu Produto', unitPrice: Math.round(valor * 100), quantity: 1 }],
split: [
{ email: 'parceiro@email.com', percentage: '10' }
],
postbackUrl: 'https://meusite.com/webhook/velani',
externalId: `pedido-${Date.now()}`,
}, {
headers: { 'x-api-key': API_KEY },
});
res.json({
transactionId: data.data.id,
pixCode: data.data.pixQrCode,
pixImage: data.data.pixQrCodeImage,
expiresAt: data.data.expiresAt,
});
});
2. Receber webhook de pagamento
app.post('/webhook/velani', (req, res) => {
const { event, data, signature } = req.body;
// Validar assinatura (recomendado)
// if (!validateWebhook(req.body, signature, 'whsec_...')) { ... }
if (event === 'transaction.paid') {
console.log('Pagamento confirmado:', data.id);
console.log('Valor:', (data.amount / 100).toFixed(2));
console.log('Pedido:', data.externalId);
// Liberar acesso ao produto/serviço
liberarAcesso(data.externalId);
}
res.status(200).json({ received: true });
});
3. Exibir QR Code no frontend
<div id="pix-container">
<h2>Escaneie o QR Code para pagar</h2>
<img id="qr-image" src="" alt="QR Code PIX" />
<p>Ou copie o código PIX:</p>
<input id="pix-code" type="text" readonly />
<button onclick="navigator.clipboard.writeText(
document.getElementById('pix-code').value
)">Copiar</button>
</div>
<script>
async function checkPayment(transactionId) {
const res = await fetch(
`/api/check-payment/${transactionId}`
);
const data = await res.json();
if (data.status === 'paid') {
window.location.href = '/obrigado';
} else {
setTimeout(() => checkPayment(transactionId), 3000);
}
}
</script>
Velani Pagamentos © 2026 · Voltar ao painel · Testar Transação