Checkout

Pix, cartão com 3DS2. Para integração browser completa, veja também @rebornpay/elements.

  1. POST /v1/checkout-sessions — cria sessão (público ou com API key)
  2. POST /v1/checkout-sessions/{id}/confirm com paymentMethod: PIX
  3. Exibir QR code / copia-e-cola e consultar status da transação

Pagamentos com cartão exigem autenticação 3DS2 no browser do comprador. O fluxo não pode ser feito 100% server-side: parte dele roda no frontend de quem integra.

  1. POST /v1/checkout-sessions — cria sessão
  2. Tokenização do cartão via PCI (PAN/CVV nunca passam pela sua API)
  3. POST .../threeds/setup — retorna deviceDataCollectionUrl e accessToken
  4. POST do accessToken (campo JWT) para deviceDataCollectionUrl em iframe oculto (~2s) — coleta de device fingerprint (DDC)
  5. POST .../threeds/authenticate — envia deviceInformation + billing + deviceChannel: BROWSER
  6. Se retornar stepUpUrl, exibir challenge (iframe/modal) e depois POST .../threeds/challenge-result
  7. POST .../confirm com cardToken e objeto threeDs (CAVV, XID, etc.)

IP do comprador: nunca confie em deviceInformation.ipAddress vindo do JavaScript. Proxie threeds/authenticate pelo seu BFF e sobrescreva o IP com o valor de x-forwarded-for / x-real-ip.

No checkout público RebornPay, o pacote @rebornpay/checkout-seon inicializa o agente SEON no browser e envia seonSession no POST .../confirm. O backend executa o Fraud API v2 antes de cobrar no gateway.

  1. initCheckoutSeon() no mount da página de checkout
  2. collectSeonSession() antes do confirm — payload Base64 no campo seonSession
  3. Tratar CHK-010 (bloqueado) e CHK-011 (revisão manual) na UI

Instale @rebornpay/checkout-3ds para reutilizar coleta de device, iframes e orquestração 3DS. O exemplo completo está na aba TypeScript em Snippets.

Shell
npm install @rebornpay/checkout-3ds

Para hosted checkout, Payment Element e headless com pk_ + clientSecret, veja o guia Reborn Elements.

Fluxo completo no browser (JavaScript / TypeScript) e exemplos server-side (Shell, Python, Rust) para as etapas de API. Compartilhe esta seção com #snippet.

const API_BASE = "https://sandbox-api.rebornpay.io";

function collectDeviceInformation() {
  const javaEnabled =
    typeof navigator.javaEnabled === "function" ? navigator.javaEnabled() : false;
  return {
    httpBrowserLanguage: navigator.language || "pt-BR",
    httpBrowserJavaEnabled: String(javaEnabled),
    httpBrowserColorDepth: String(screen.colorDepth),
    httpBrowserScreenHeight: String(screen.height),
    httpBrowserScreenWidth: String(screen.width),
    httpBrowserTimeDifference: String(new Date().getTimezoneOffset()),
    userAgentBrowserValue: navigator.userAgent,
    httpAcceptContent: "*/*",
    ipAddress: "0.0.0.0", // seu BFF deve sobrescrever com o IP real
  };
}

function waitForDeviceCollection(url, accessToken) {
  return new Promise((resolve, reject) => {
    const iframeName = `reborn-3ds-ddc-${crypto.randomUUID()}`;
    const iframe = document.createElement("iframe");
    iframe.name = iframeName;
    iframe.style.cssText = "display:none;width:1px;height:1px;border:0";
    const form = document.createElement("form");
    form.method = "POST";
    form.action = url;
    form.target = iframeName;
    form.style.display = "none";
    const jwt = document.createElement("input");
    jwt.type = "hidden";
    jwt.name = "JWT";
    jwt.value = accessToken;
    form.appendChild(jwt);
    let settled = false;
    const cleanup = () => { form.remove(); iframe.remove(); };
    iframe.onload = () => {
      if (settled) return;
      settled = true;
      setTimeout(() => { cleanup(); resolve(); }, 2000);
    };
    iframe.onerror = () => {
      if (settled) return;
      settled = true;
      cleanup();
      reject(new Error("3DS device collection failed"));
    };
    document.body.appendChild(iframe);
    document.body.appendChild(form);
    form.submit();
  });
}

function runChallengeStepUp(stepUpUrl) {
  return new Promise((resolve) => {
    const iframe = document.createElement("iframe");
    iframe.title = "Autenticação 3DS";
    iframe.src = stepUpUrl;
    iframe.style.cssText =
      "position:fixed;inset:0;width:100%;height:100%;z-index:9999;border:0;background:#fff";
    iframe.onload = () => setTimeout(() => { iframe.remove(); resolve(); }, 8000);
    document.body.appendChild(iframe);
  });
}

async function api(path, { method = "GET", body, apiKey } = {}) {
  const res = await fetch(`${API_BASE}${path}`, {
    method,
    headers: {
      "Content-Type": "application/json",
      ...(apiKey ? { "X-Api-Key": apiKey } : {}),
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

async function payWithCard({ paymentLinkId, cardToken, buyer, returnUrl, apiKey }) {
  const session = await api("/v1/checkout-sessions", {
    method: "POST",
    apiKey,
    body: {
      paymentLinkId,
      customer: {
        name: buyer.name,
        email: buyer.email,
        document: buyer.document.replace(/\D/g, ""),
      },
    },
  });

  const sessionId = session.sessionId;

  const setup = await api(`/v1/checkout-sessions/${sessionId}/threeds/setup`, {
    method: "POST",
    apiKey,
    body: { slugToken: cardToken },
  });

  await waitForDeviceCollection(setup.deviceDataCollectionUrl, setup.accessToken);

  const auth = await api(
    `/v1/checkout-sessions/${sessionId}/threeds/authenticate?paymentMethod=CREDIT_CARD`,
    {
      method: "POST",
      apiKey,
      body: {
        slugToken: cardToken,
        returnUrl,
        deviceChannel: "BROWSER",
        deviceInformation: collectDeviceInformation(),
        billing: buyer.billing,
      },
    },
  );

  let threeDs;
  if (auth.xid && auth.cavv && auth.directoryServerTransactionId) {
    threeDs = {
      xid: auth.xid,
      cavv: auth.cavv,
      cavvResultCode: "2",
      secureVersion: auth.specificationVersion ?? "2.1.0",
      directoryServerTransactionId: auth.directoryServerTransactionId,
      threeDsServerTransactionId: auth.authenticationTransactionId,
    };
  } else {
    if (auth.stepUpUrl) await runChallengeStepUp(auth.stepUpUrl);
    const challenge = await api(
      `/v1/checkout-sessions/${sessionId}/threeds/challenge-result`,
      {
        method: "POST",
        apiKey,
        body: { authenticationTransactionId: auth.authenticationTransactionId },
      },
    );
    threeDs = {
      xid: challenge.xid,
      cavv: challenge.cavv,
      cavvResultCode: "2",
      secureVersion: challenge.secureVersion,
      directoryServerTransactionId: challenge.directoryServerTransactionId,
      threeDsServerTransactionId: challenge.threeDsServerTransactionId,
    };
  }

  return api(`/v1/checkout-sessions/${sessionId}/confirm`, {
    method: "POST",
    apiKey,
    body: {
      paymentMethod: "CREDIT_CARD",
      installments: 1,
      cardToken,
      threeDs,
    },
  });
}

Schemas e parâmetros em API Reference → Checkout Sessions → 3DS.