docs

Hosted Checkout

Sem construir front — gera link pelo dashboard, redireciona, recebe webhook quando paga. White-label com sua marca.

Cenário: você não quer construir tela de checkout — gera um link, redireciona o cliente, recebe webhook quando ele paga.

A Zhex já tem checkout hosted em produção (zhx-checkout) — é a tela onde o cliente vê o produto, escolhe método de pagamento (PIX/cartão/boleto) e finaliza. Você integra fazendo o cliente chegar até esse link.

Hoje via dashboard, API V1 pública em roadmap

A criação programática de Payment Links com shape Stripe-style (POST /v1/payment_links com line_items, after_completion, etc.) é roadmap. Hoje, links de checkout são criados pelo dashboard da Zhex (Produtos → Links de pagamento). Esta página descreve esse fluxo — quando a API V1 entrar, expandimos para cobrir programatic creation.

Fluxo atual

Em Produtos → escolha o produto → Links de pagamento → Criar:

  • Configure métodos aceitos (PIX, cartão, boleto)
  • Defina quantity fixa ou flexível
  • Ative cupom (allow_promotion_codes)
  • Escolha o redirect_url pós-pagamento (https://meusite.com/obrigado?intent={PAYMENT_INTENT_ID})
  • Copie a URL gerada (algo como https://buy.zhex.com/c/lnk_…)

A URL do link é estável — você pode reusá-la em campanhas, emails, anúncios, sem expirar até desativar manualmente no dashboard.

2. Redirecione o usuário

// no seu app, quando o cliente clicar em "Comprar":
res.redirect('https://buy.zhex.com/c/lnk_seu_link');

A página é hospedada pela Zhex e renderiza o checkout completo: identificação do cliente, escolha de método, tokenização (@zhexio/zhex-js por baixo), confirmação de PIX/3DS/boleto e tela de obrigado.

3. Webhook de retorno

A confirmação de pagamento chega via webhook normal — não há checkout_session.* separado:

import Zhex from '@zhexio/node';

app.post(
  '/webhooks/zhex',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    const event = Zhex.webhooks.constructEvent(
      req.body,
      req.headers['zhex-signature'] as string,
      process.env.ZHEX_WEBHOOK_SECRET!,
    );

    if (event.type === 'payment_intent.succeeded') {
      const intent = event.data.object as { id: string; customer: string | null; amount: number };
      // Cliente pagou. Use intent.id para correlacionar com o pedido.
      await registrarPedidoPago(intent.id, intent.customer, intent.amount);
    }

    res.json({ received: true });
  },
);

O redirect_url que o cliente vê no fim do fluxo recebe o payment_intent_id na query string — útil pra mostrar tela de "obrigado, seu pedido X foi confirmado", mas fonte da verdade ainda é o webhook: nunca confie no redirect (cliente pode fechar o navegador antes de chegar lá).

Branding

Configurável no dashboard em Configurações → Branding:

  • Logo (PNG/SVG)
  • Cor primária (hex)
  • Domínio custom (CNAME apontando para buy.zhex.com) — disponível em planos avançados

A página segue o seu visual em qualquer link gerado, sem mudança no código.

Modos suportados hoje

Tipo de produtoComportamento do checkout
Produto ONE_TIME (digital ou físico)Cobrança única; payment_intent.succeeded no fim
Produto RECURRING (com Subscription template configurado)Cria CustomerSubscription no sucesso da primeira cobrança
Produto INSTALLMENTCobrança parcelada no cartão; primeira parcela imediata

Modo "setup" (salvar cartão sem cobrar) é roadmap.

Pitfalls comuns

  • Não tratar payment_intent.payment_failed. Cliente pode tentar 3 vezes no mesmo link, falhar todas e abandonar. Webhook avisa pra você fazer follow-up por email.
  • Esquecer do payment_intent_id na URL de retorno. Sem ele, sua tela de "obrigado" não consegue correlacionar com o pedido.
  • Pré-encher dados do cliente — hoje, o link não aceita pré-fill via query string. Cliente sempre digita os dados na primeira vez. Pré-fill é roadmap.

Eventos a tratar

EventoQuandoAção
payment_intent.succeededPagamento concluído (PIX/cartão/boleto)Registrar pedido pago, liberar produto
payment_intent.payment_failedÚltima tentativa falhouEmail de follow-up "tente novamente"
payment_intent.canceledLink expirou (PIX/boleto) ou cliente cancelouMarcar pedido como abandonado
Esta página foi útil?

Atualizado em

Nesta página