Os callbacks recebem o resultado do pagamento. Cada um é async. Alguns recebem um objeto actions para controlar o botão ou reagir ao fecho do popup.
Esta referência segue a implementação JavaScript atual da SDK (Button.js), que é a fonte autoritativa. As definições TypeScript no repositório estão desatualizadas.

createOrder

createOrder: () => Promise<string | null>
Chamado antes de abrir o popup. Cria a ordem no teu backend e devolve um identificador de transação (o merchantTransactionId) — a SDK guarda-o como paymentOrderId e usa-o no fluxo.
Tem de devolver uma string não-vazia. Se devolveres null, undefined ou '', o popup não avança.
async createOrder() {
  const r = await fetch('/api/facipay/create-order', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ items: cart }),
  });
  if (!r.ok) throw new Error('Falha ao criar ordem');
  const { referenceNumber } = await r.json();
  return referenceNumber; // usado como paymentOrderId
}

onApprove

onApprove: (data, actions) => Promise<void>
Pagamento aprovado. data tem a forma { payment: { orderId, status, type, data } }. actions expõe apenas onPopupWindowClosed.
data.payment.orderId
string
O paymentOrderId (o valor devolvido por createOrder).
data.payment.status
string
Estado do pagamento (paymentStatus).
data.payment.type
string
Tipo de pagamento (tpPayment) — dir | mcx | ref.
data.payment.data
object
Dados do pagamento (paymentData): referência, entidade, valor, etc.
actions.onPopupWindowClosed(cb)
function
Regista uma função a correr quando o popup fecha — o sítio certo para redirecionar.
async onApprove(data, actions) {
  actions.onPopupWindowClosed(() => {
    window.location.href = `/sucesso?orderId=${data.payment.orderId}`;
  });
}

onPending

onPending: (data, actions) => Promise<void>
Pagamento pendente (Referência EMIS). Mesma forma de onApprove: { payment: { orderId, status, type, data } }. Os dados da referência estão em data.payment.data.
data.payment.data.paymentReference
string
A referência a mostrar ao cliente.
data.payment.data.entity.number
string
Número da entidade.
data.payment.data.entity.name
string
Nome da entidade.
data.payment.data.amount
number
Valor a pagar.
async onPending(data, actions) {
  actions.onPopupWindowClosed(() => {
    const ref = data.payment.data.paymentReference;
    const entity = data.payment.data.entity.number;
    window.location.href = `/pendente?ref=${ref}&entity=${entity}`;
  });
}

onCancel

onCancel: (data) => Promise<void>
O utilizador cancelou (evento PAYMENT_CANCELED) ou fechou o popup sem concluir. Reabre o carrinho ou mostra um CTA para tentar de novo.
async onCancel(data) {
  window.location.href = '/cancelado';
}

onError

onError: (data) => Promise<void>
Erro na transação (evento PAYMENT_ERROR ou falha ao abrir o popup).
async onError(error) {
  console.error('FaciPay error:', error);
  showToast('Ocorreu um erro. Tenta novamente.', 'error');
}

onInit

onInit: (actions) => Promise<void>
Botão inicializado. actions expõe enable() e disable().
async onInit(actions) {
  if (!cartIsValid) actions.disable();
}

onClick

onClick: (data, actions) => Promise<void>
Disparado no clique, antes do createOrder(). actions expõe enable(), disable() e reject(). Chamar actions.reject() interrompe o fluxo (o popup não abre) — ideal para validar formulários.
actions.reject()
function
Interrompe a sequência do botão (cancela este clique).
async onClick(data, actions) {
  const customer = validateCustomerForm();
  if (!customer) {
    actions.reject();          // cancela o fluxo deste clique
    return;
  }
  facipay.button.addCustomerInfo({ name: customer.name, phone: customer.phone });
}

Próximo passo: Objeto Button

render, destroy, referências, cliente e actions.