Quickstart
Sua primeira cobrança em 5 minutos com cURL ou Node 18+ fetch — sem SDK, sem dependência.
Este guia leva você de zero à primeira cobrança bem-sucedida em modo de teste, sem nenhuma adquirente real envolvida. No final, você terá:
- Uma chave de API de teste (
zsk_test_*). - Um
PaymentIntentcriado via API. - Um webhook recebido no seu servidor local com a confirmação do pagamento.
Tudo em HTTP puro — curl ou fetch nativo do Node 18+. Sem SDK, sem dependência.
Modo de teste vs. modo live
Tudo neste guia usa chaves *_test_*. Elas tocam o MockAcquirerAdapter interno — você nunca vai mover dinheiro real. Para ir para produção é só trocar pela chave zsk_live_*.
1. Crie sua conta e pegue uma chave
Crie sua conta em app.zhex.io e vá em Developers → API keys.
Você verá quatro tipos de chaves:
| Prefixo | Uso | Onde |
|---|---|---|
zk_test_… | Publishable, modo teste | Front-end (ex.: zhex.js) |
zsk_test_… | Secret, modo teste | Servidor (somente backend!) |
zk_live_… | Publishable, produção | Front-end |
zsk_live_… | Secret, produção | Servidor |
Copie a chave zsk_test_… e guarde como variável de ambiente:
export ZHEX_SECRET_KEY=zsk_test_abcd1234efgh5678Nunca commite chaves secretas
zsk_* deve viver apenas em variáveis de ambiente do servidor. A Zhex monitora chaves vazadas no GitHub via Secret Scanning — se sua chave for detectada em commit público ela é revogada automaticamente.
2. Crie um Customer
Antes de cobrar, crie o cliente — customer é parâmetro obrigatório no PaymentIntent.
curl https://prometheus.zhex.io/v1/customers \
-H "Authorization: Bearer $ZHEX_SECRET_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"email": "cliente@exemplo.com.br",
"name": "Cliente Teste",
"document": "12345678909"
}'3. Faça sua primeira cobrança
Crie um PaymentIntent de R$ 49,90 em PIX, apontando para o customer recém-criado.
curl https://prometheus.zhex.io/v1/payment_intents \
-H "Authorization: Bearer $ZHEX_SECRET_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Zhex-Version: 2026-04-25" \
-H "Content-Type: application/json" \
-d '{
"amount": 4990,
"currency": "brl",
"customer": "cus_…",
"payment_method_types": ["pix"],
"description": "Primeira cobrança Zhex"
}'A resposta vai ter o seguinte formato:
{
"id": "pi_3MtwBwLkdIwHu7ix28a3tqPa",
"object": "payment_intent",
"livemode": false,
"amount": 4990,
"currency": "brl",
"status": "requires_payment_method",
"customer": "cus_…",
"description": "Primeira cobrança Zhex",
"payment_method_types": ["pix"],
"last_payment_error": null,
"charges": { "latest": null },
"created": 1714057200
}Para liquidar em test mode, dispare o helper:
curl -X POST "https://prometheus.zhex.io/v1/test_helpers/payment_intents/pi_…/succeed" \
-H "Authorization: Bearer $ZHEX_SECRET_KEY"
# webhook payment_intent.succeeded é entregue em segundos4. Receba o webhook de confirmação
Em vez de ficar fazendo polling no GET /v1/payment_intents/:id, você recebe um evento HTTP assim que o pagamento confirma.
3.1. Crie o endpoint local
import express from 'express';
import { createHmac, timingSafeEqual } from 'node:crypto';
const app = express();
app.post(
'/webhooks/zhex',
// CRÍTICO: raw body. express.json() quebra a assinatura.
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.header('zhex-signature') ?? '';
const parts = Object.fromEntries(
sig.split(',').map((kv) => kv.split('=')),
) as { t?: string; v1?: string };
const secret = process.env.ZHEX_WEBHOOK_SECRET!;
const body = req.body.toString('utf8');
const expected = createHmac('sha256', secret)
.update(`${parts.t}.${body}`)
.digest('hex');
const a = Buffer.from(parts.v1 ?? '', 'hex');
const b = Buffer.from(expected, 'hex');
if (a.length !== b.length || !timingSafeEqual(a, b)) {
return res.status(400).send('Invalid signature');
}
const event = JSON.parse(body);
if (event.type === 'payment_intent.succeeded') {
const intent = event.data.object;
console.log('PIX confirmado:', intent.id, intent.amount);
}
res.json({ received: true });
},
);
app.listen(3000, () => console.log('Listening on http://localhost:3000'));3.2. Exponha o localhost com ngrok (ou cloudflared)
Pra dev local, use um tunnel HTTPS pra expor seu localhost e cadastre um webhook endpoint apontando pra ele:
# Em um terminal: sobe seu app
node server.js
# Em outro: tunnel pra porta 3000
ngrok http 3000
# → Forwarding https://abc123.ngrok-free.app -> http://localhost:30003.3. Cadastre o endpoint na Zhex
curl https://prometheus.zhex.io/v1/webhook_endpoints \
-H "Authorization: Bearer $ZHEX_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://abc123.ngrok-free.app/webhooks/zhex",
"events": ["payment_intent.succeeded", "payment_intent.payment_failed"]
}'Response:
{
"id": "we_1MtwBwLkdI",
"url": "https://abc123.ngrok-free.app/webhooks/zhex",
"secret": "whsec_test_xyz123...",
"events": ["payment_intent.succeeded", "payment_intent.payment_failed"],
"livemode": false
}Exporte o whsec_*:
export ZHEX_WEBHOOK_SECRET=whsec_test_xyz123...E reinicie seu app pra ele pegar o env atualizado.
5. Pagamento confirmado
Em test mode, o mock acquirer "paga" o PIX automaticamente após ~3s da criação do PaymentIntent. Você verá no terminal:
PIX confirmado: pi_3MtwBwLkdIwHu7ix28a3tqPa 4990E pode confirmar via API:
curl https://prometheus.zhex.io/v1/payment_intents/pi_3MtwBwLkdIwHu7ix28a3tqPa \
-H "Authorization: Bearer $ZHEX_SECRET_KEY"
# → "status": "succeeded"- Pegou a chave
zsk_test_…e exportou no env. - Criou um PaymentIntent via
fetchcomIdempotency-Key. - Recebeu o webhook com tunnel + assinatura HMAC validada.
- Confirmou o pagamento quando
payment_intent.succeededchegou.
Próximos passos
Conceitos
Entenda PaymentIntent, idempotência, webhooks e modos de teste.
Cartões com Zhex Elements
Cobrança com cartão sem PCI escopo expandido.
Referência da API
Todos os endpoints e shapes da API V1.
Indo para produção
Checklist antes de trocar para `zsk_live_*`.
Atualizado em