Test mode
Test keys, MockAcquirerAdapter e cartões 4242 — 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 |
|---|---|
4242 4242 4242 4242 | Visa, sucesso direto |
5555 5555 5555 4444 | Mastercard, sucesso |
Declines
| PAN | decline_code |
|---|---|
4000 0000 0000 0002 | card_declined (genérico) |
4000 0000 0000 9995 | insufficient_funds |
4000 0000 0000 9987 | lost_card |
4000 0000 0000 9979 | stolen_card |
4000 0000 0000 0069 | expired_card |
4000 0000 0000 0127 | incorrect_cvc |
4000 0000 0000 0119 | processing_error (retryable) |
3DS
| PAN | Comportamento |
|---|---|
4000 0000 0000 3220 | Força requires_action (3DS challenge) |
Chargeback
| PAN | Comportamento |
|---|---|
4000 0000 0000 0259 | Sucesso + simula charge.dispute.created |
4000 0000 0000 1976 | 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 4000 0000 0000 3220 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