Test mode
Test keys, MockAcquirerAdapter e cartões 4929 (BIN brasileiro) — como simular sucesso, decline, 3DS, chargeback e PIX/boleto sem tocar adquirente real.
Test mode é first-class na Zhex. Cada par de chaves (zk_test_* / zsk_test_*) opera num espaço isolado do ambiente de produção: dados de teste não vazam para reports financeiros, webhooks usam whsec_test_* separado, e a smart routing roteia tudo para o MockAcquirerAdapter em vez de adquirente real.
A regra mental é: test mode toca o mesmo Postgres que live, mas com livemode: false em todas as entidades. Você lista, retrieve, refunde, faz tudo igual — só não há dinheiro real movendo.
Test keys
No dashboard, Developers → API keys mostra os pares:
| Prefixo | Onde usar |
|---|---|
zk_test_* | Publishable, frontend (zhex.js em test) |
zsk_test_* | Secret, server-side em test |
whsec_test_* | Webhook signing em test (gerado por endpoint criado em test mode) |
A Zhex rejeita uso cruzado: chave de um modo tentando acessar entidades do outro retorna 404 (genérico — não confirma existência cross-mode, evita leak).
Cartões de teste
A Zhex implementa o conjunto Stripe de PANs de teste — qualquer dev acostumado já reconhece. CVV pode ser qualquer 3 dígitos (4 para Amex), validade qualquer mês/ano no futuro.
Sucessos
| PAN | Comportamento |
|---|---|
4929 9999 9999 9991 | Visa, sucesso direto |
5151 5151 5151 5155 | Mastercard, sucesso |
Declines
| PAN | decline_code |
|---|---|
4929 0000 0000 0000 | card_declined (genérico) |
4929 0000 0000 0091 | insufficient_funds |
4929 0000 0000 0083 | lost_card |
4929 0000 0000 0075 | stolen_card |
4929 0000 0000 0067 | expired_card |
4929 0000 0000 0059 | incorrect_cvc |
4929 0000 0000 0042 | processing_error (retryable) |
3DS
| PAN | Comportamento |
|---|---|
4929 0000 0000 3004 | Força requires_action (3DS challenge) |
Chargeback
| PAN | Comportamento |
|---|---|
4929 0000 0000 2501 | Sucesso + simula charge.dispute.created |
4929 0000 0000 1909 | Sucesso + simula chargeback product_not_received |
Chargebacks de teste seguem o mesmo modelo de produção: reembolso compulsório, sem direito de resposta. Use para validar seu handler de charge.dispute.created (registro contábil, email para o cliente, revogação de acesso).
PIX em test mode
Não há QR real para escanear — você dispara o pagamento via test helper:
import { randomUUID } from 'node:crypto';
// 1. crie um intent PIX normalmente (com customer já existente)
const intent = await zhex.paymentIntents.create({
amount: 4990,
currency: 'brl',
customer: 'cus_…',
payment_method_types: ['pix'],
});
// 2. simule pagamento bem-sucedido
await fetch(
`https://prometheus.zhex.io/v1/test_helpers/payment_intents/${intent.id}/succeed`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ZHEX_TEST_KEY}`,
'Idempotency-Key': randomUUID(),
},
},
);
// dispara webhook payment_intent.succeeded com livemode: falseOutras transições disponíveis em /v1/test_helpers/payment_intents/:id/:
| Endpoint | Resultado |
|---|---|
succeed | payment_intent.succeeded |
fail | payment_intent.payment_failed com decline_code: insufficient_funds |
expire | payment_intent.canceled (timeout PIX/boleto) |
Test helpers só aceitam zsk_test_*/zrk_test_*. Chaves live retornam 403 test_mode_only.
Boleto em test mode
// 1. customer com document + endereço
const intent = await zhex.paymentIntents.create({
amount: 4990,
currency: 'brl',
customer: 'cus_…',
payment_method_types: ['boleto'],
});
// 2. simular pagamento via test helper
await fetch(
`https://prometheus.zhex.io/v1/test_helpers/payment_intents/${intent.id}/succeed`,
{
method: 'POST',
headers: { Authorization: `Bearer ${process.env.ZHEX_TEST_KEY}` },
},
);PDFs reais não são gerados em test mode hoje — a renderização do boleto é função do checkout hosted, e em test mode ele exibe placeholders. O fluxo de webhook (payment_intent.succeeded) é o que importa para validar a integração.
Webhooks em test mode
Endpoints criados via Integrações → Webhooks com a chave zsk_test_* recebem só eventos livemode: false. Boa prática:
- Endpoint A (live):
https://api.meusite.com/webhooks/zhex—whsec_live_* - Endpoint B (test):
https://abc123.ngrok-free.app/webhooks/zhex—whsec_test_*
Ambos recebem o mesmo formato de evento. O campo livemode: false no payload permite seu handler decidir se aciona side effects reais (envio de email com nota fiscal, integração com SAP) ou apenas log.
if (!event.livemode) {
console.log('[test] event:', event.type);
return res.status(200).end();
}
// fluxo real de produçãoMode toggle no dashboard
O canto superior do dashboard mostra um toggle TEST / LIVE com banner amarelo no topo da tela em test. Listings (Transações, Customers, Produtos) filtram automaticamente pelo modo selecionado.
Limpeza de dados de teste
Test data nunca expira automaticamente (decisão deliberada — facilita debug de bug intermitente que aconteceu há 2 meses). Para limpar:
- Manual no dashboard: Developers → Test data → Wipe. Confirma com
WIPEdigitado. - API: roadmap. Quando entrar, vai ficar em
POST /v1/test_helpers/wipecom exclusão assíncrona.
Checklist antes de virar live
Antes de trocar zsk_test_* por zsk_live_* em produção:
Endpoints de webhook configurados em ambos os modos
Não esqueça do live. É erro clássico criar só o endpoint de test e mandar produção sem nenhum.
Fluxo 3DS testado
Use 4929 0000 0000 3004 para forçar requires_action e garantir que seu fluxo de retorno (via webhook payment_intent.succeeded) funciona.
Idempotency keys batem com sua estratégia de retry
Reuse a mesma Idempotency-Key em retries — sem isso, network flake duplica cobrança.
Erros declinados são tratados
Cliente vê mensagem útil em PT-BR, não card_declined cru.
Eventos críticos têm logs e alertas
payment_intent.succeeded, payment_intent.payment_failed, charge.dispute.created no mínimo.
Próximos passos
PaymentIntent
Lifecycle e statuses para testar
Webhooks
Verificação HMAC com whsec_test_*
GA Checklist
Indo para live mode com confiança
Atualizado em