Celetus • Documentação

Crie sua própria página de upsell

Um SDK JavaScript leve para você montar o upsell pós-compra com HTML e CSS do seu jeito. Aceita PIX e cartão one-click, emite eventos de pagamento e cabe em qualquer stack — HTML puro, React ou WordPress.

Como funciona em 30 segundos

No painel Celetus, em Funil de vendas, clique no ícone </> da etapa e copie a key. Cole no init() e monte o HTML/JS como quiser — o SDK cuida de buscar dados do passo, criar o pedido e acompanhar o pagamento.

<script src="https://pay.celetus.com/assets/js/celetus.upsell.sdk.js"></script>
<script>
  const upsell = CeletusUpsell.init({
    key: "SUA_KEY_AQUI" // ← copiada do painel Celetus (etapa do funil)
  });

  upsell.loadStep().then(step => {
    document.getElementById("titulo").textContent = step.productName;
    document.getElementById("preco").textContent  = step.valueFormatted;
  });

  upsell.on("qrReady", ({ pixQrUrl, pixQrCode }) => {
    // pixQrUrl pode ser uma URL http OU um código copia-e-cola.
    document.getElementById("qr").src = pixQrUrl && pixQrUrl.startsWith("http")
      ? pixQrUrl
      : ""; /* use qrcode.js para gerar a partir do código copia-e-cola */
  });

  upsell.on("paid",   () => upsell.next());  // avança para a próxima etapa
  upsell.on("failed", ({ reason }) => alert("Falhou: " + reason));

  document.getElementById("sim").onclick = () => upsell.accept();
  document.getElementById("nao").onclick = () => upsell.decline(); // próxima etapa (recusa)
</script>

Parâmetros do init()

Parâmetro Obrigatório Descrição
key Sim Identificador da etapa do funil. Copie no painel Celetus clicando no ícone </> da etapa. Fica hardcoded no seu código — mesma mecânica que hoje é usada no widget iframe com Upsell.Widget.show({ key }).
sfid Não Identificador da compra original. Lido automaticamente de ?sfid=… na URL (plantado pelo redirect do checkout pós-compra). Em iframes srcdoc (Framer/Wix), o SDK faz fallback para window.parent.location.search. Single-use: cada sfid permite carregar os dados do passo uma única vez (ver seção abaixo).

Pré-requisitos

⚠️ Link de uso único (importante para testes)

Por segurança, cada compra gera um link de upsell que pode ser carregado uma única vez — isso impede que o cliente compartilhe o link com outras pessoas. Uma segunda chamada ao backend retorna erro.

Para que reloads de página não quebrem o fluxo do cliente real, o SDK mantém um cache em localStorage com TTL de 1 minuto. Dentro dessa janela você pode recarregar a página à vontade que os dados continuam disponíveis. Após 1 minuto, o cache expira e o link original não pode mais ser reusado.

Se você vê "Link inválido ou já consumido"

Se precisar forçar nova tentativa dentro da janela de cache (casos raros de recuperação de erro), chame upsell.clearStepCache() antes do próximo loadStep(). Isso não recupera um link já consumido no backend — só limpa a cópia local.

Eventos disponíveis

Evento Payload Quando dispara
stepLoaded step Após loadStep() resolver.
accepted charge Após o pedido de upsell ser criado com sucesso.
qrReady { pixQrCode, pixQrUrl, charge } PIX: código disponível (imediato ou via polling).
statusChange { status, charge } Cada atualização de status durante o acompanhamento.
paid { charge } Status terminou em paid ou overpaid.
failed { charge, reason } Status terminou em canceled, failed, chargedback, etc.
expired — Tempo limite de acompanhamento atingido (default 15min).
redirecting { redirectUrl, direction: "positive" } Antes de avançar para a próxima etapa no caminho positivo (após paid).
declined { redirectUrl, direction: "negative" } Antes de avançar no caminho negativo (decline()).
error Error Qualquer falha de rede ou HTTP não-ok.

Encadeamento entre etapas do funil

Um funil de upsell tipicamente tem várias etapas em sequência (ex: etapa 1 → etapa 2 → obrigado). Depois do cliente aceitar ou recusar uma etapa, o SDK já sabe para onde ir — basta você chamar upsell.next():

// Caminho positivo (após pagamento confirmado)
upsell.on("paid", () => {
  // Opcional: mostre uma mensagem de sucesso por alguns segundos
  document.getElementById("pago").hidden = false;
  setTimeout(() => upsell.next(), 1500); // avança para a próxima etapa
});

// Caminho negativo (cliente clicou em "Não, obrigado")
document.getElementById("nao").onclick = () => upsell.decline();

As URLs da próxima etapa (positiva e negativa) são configuradas no painel Celetus no próprio passo do funil — você não precisa hardcodar caminhos no seu código. O SDK expõe as URLs resolvidas em step.positivePageUrl e step.negativePageUrl após o loadStep(), caso você queira renderizar um <a href> ao invés de redirecionar via JS.

Ordem de prioridade

A query string atual é preservada no redirect (exceto ?key=, que é substituída pela key da próxima etapa). Isso garante que parâmetros como ?sfid=… e UTMs cheguem intactos na etapa seguinte.

Controle fino

// Forçar direção
upsell.next({ direction: "positive" });
upsell.next({ direction: "negative" });

// URL customizada (ignora config do painel)
upsell.next({ redirectUrl: "/minha-pagina-de-obrigado" });

// Só calcular a URL sem redirecionar (útil para <a href>)
const url = upsell.next({ noRedirect: true });

PIX: dois formatos possíveis

O evento qrReady entrega dois campos:

Detecte com pixQrUrl.startsWith("http"): se for URL, use <img src>; senão, use uma lib como qrcode para gerar a imagem do copia-e-cola.

Checklist de debug