Os campos payerName e payerDocument na criação do PIX não precisam ser verídicos. Eles servem apenas para preencher a cobrança. Os dados reais do pagador são capturados automaticamente após a confirmação do pagamento.
Solicitar Saque (Cash-out)
POST/merchant/cashout
Dois modos: sessão do painel (CSRF + PIN) ou server-to-server (ci/cs nos headers).
Assinatura HMAC-SHA256 no formato t=<timestamp>,v1=<hash>
X-VexoPay-Event
Nome do evento (ex.: payment.completed)
Para onde o webhook é enviado
Você pode configurar o webhook de duas formas, na página API Keys:
Opção
Onde configurar
Quando é usada
Webhook da conta
Card Webhook, na página API Keys
Padrão. Recebe os eventos de todas as chaves que não tiverem URL própria.
Webhook por chave
Na tabela de chaves: ⋯ → Configurar webhook
Só para cobranças criadas com aquela chave. Quando existe, substitui o da conta.
A URL é decidida no momento em que a cobrança é criada e fica gravada nela. Trocar a URL depois não muda para onde as cobranças que já existem serão entregues. Vale tanto para PIX quanto para cripto.
Verificando a assinatura
Cada entrega é assinada com o whsec_...correspondente à URL que recebeu o evento: se a cobrança usou o webhook de uma chave, a assinatura é feita com o segredo daquela chave; caso contrário, com o segredo da conta. Os dois ficam na página API Keys.
A verificação é opcional e não altera o corpo do webhook — se você já processa sem verificar, nada muda. Recomendamos ativar para garantir que a chamada veio mesmo da VexoPay.
A assinatura é o HMAC-SHA256 de timestamp + "." + corpo_bruto. Compare sempre sobre o corpo exato recebido (não re-serialize o JSON) e rejeite entregas com mais de 5 minutos para evitar replay.
// Node.js (Express) — use o corpo BRUTO, não o JSON já parseadoconst crypto = require('crypto');
const SECRET = process.env.VEXOPAY_WEBHOOK_SECRET; // whsec_...
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const body = req.body.toString('utf8');
const header = req.headers['x-vexopay-signature'] || '';
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const age = Math.abs(Math.floor(Date.now()/1000) - Number(parts.t));
if (age > 300) return res.sendStatus(400); // replayconst expected = crypto.createHmac('sha256', SECRET)
.update(parts.t + '.' + body).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 || ''));
if (!ok) return res.sendStatus(401);
const evento = JSON.parse(body);
// ... processa o evento ...
res.sendStatus(200);
});
A VexoPay considera a entrega bem-sucedida quando seu endpoint responde 2xx em até 10 segundos. Fora disso, a entrega é reenviada — então o mesmo evento pode chegar mais de uma vez. Trate o processamento como idempotente: use o transactionId como chave e ignore o que já processou.
Criar Cobrança Crypto
POST/gateway/crypto-create
Gera uma cobrança em USDT, USDC, BTC ou TRX com cotação Binance em tempo real.
O cliente deve enviar exatamente o amount retornado (com os últimos
decimais únicos). Esse "amount tagging" é como identificamos o pagamento no endereço compartilhado.
Status Cobrança Crypto
GET/gateway/crypto-status?id=<invoice_id>
Consulta o estado da cobrança. Recomendado fazer polling a cada 30s até receber paid.