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
-
O funil de upsell precisa estar cadastrado no painel do produtor
com a etapa ativa. Copie a
keyno ícone</>da etapa. -
A página de upsell customizada precisa receber
?sfid=…na URL. O redirect do checkout principal faz isso automaticamente após a compra. -
Se a sua página roda dentro de um iframe srcdoc
(Framer/Wix HTML embed), o SDK já faz o fallback para
window.parent.location.searchpara capturar osfid.
⚠️ Link de uso único (importante para testes)
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"
-
Em teste: crie uma nova compra no seu produto
para obter um
sfidnovo. Cada teste precisa de um link fresco. - Em produção: o cliente abriu o link, fechou e tentou reabrir depois de 1 minuto. Esse é o comportamento esperado — o link é single-use.
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
-
Positivo (pós-paid):
step.positivePageUrl→charge.urlRedirect→ página de obrigado padrão do Celetus -
Negativo (pós-decline):
step.negativePageUrl→ página de obrigado padrão
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:
-
pixQrUrl— em alguns casos vem como URLhttp(s)://…apontando para uma imagem do QR Code; em outros vem como código copia-e-cola (string). -
pixQrCode— sempre o código copia-e-cola (útil para o botão "copiar chave").
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
-
Nenhum evento dispara? Abra o console: o SDK
emite um
errorse falta algum dado essencial. - CORS bloqueando? O domínio da sua página precisa estar liberado. Abra um chamado com o time Celetus passando o domínio exato.
-
Query string some no iframe? O SDK já faz
fallback para
window.parent, mas se o iframe estiver em outra origem, pode ser necessário plantar osfiddiretamente na URL do iframe. -
QR não aparece? O
pixQrUrlpode ser uma URL http ou um código copia-e-cola. Cheque comstartsWith("http").