Depois do pagamento, redirecionas o cliente para uma de três páginas. Usa actions.onPopupWindowClosed() para redirecionar só quando o popup fecha.

/sucesso

Lê o orderId, confirma o estado no backend (a fonte da verdade é o webhook) e mostra a confirmação.
async onApprove(data, actions) {
  actions.onPopupWindowClosed(() => {
    window.location.href = `/sucesso?orderId=${data.payment.orderId}`;
  });
}
/sucesso (cliente)
const orderId = new URLSearchParams(location.search).get('orderId');
const r = await fetch(`/api/facipay/order/${orderId}/status`);
const { status } = await r.json();
if (status === 'CON') showConfirmed();
else showStillProcessing();

/pendente (Referência EMIS)

Mostra entidade + referência + valor bem visíveis. Faz polling de fallback ao endpoint de estado e redireciona para /sucesso quando CON.
async onPending(data, actions) {
  actions.onPopupWindowClosed(() => {
    const ref = data.payment.data.paymentReference;
    const entity = data.payment.data.entity.number;
    const amount = data.payment.data.amount;
    window.location.href = `/pendente?ref=${ref}&entity=${entity}&amount=${amount}`;
  });
}
/pendente (polling de fallback)
const orderId = new URLSearchParams(location.search).get('orderId');
const poll = setInterval(async () => {
  const r = await fetch(`/api/facipay/order/${orderId}/status`);
  const { status } = await r.json();
  if (status === 'CON') {
    clearInterval(poll);
    window.location.href = `/sucesso?orderId=${orderId}`;
  }
}, 7000); // 5–10s
O polling é apenas rede de segurança caso o webhook atrase. A confirmação autoritativa continua a vir do webhook no teu backend.

/cancelado

Mensagem clara e um CTA para tentar de novo.
async onCancel() {
  window.location.href = '/cancelado';
}

Próxima receita: Referências múltiplas

Mostrar o valor e vários itens no botão.