> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.credify.com.br/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.credify.com.br/_mcp/server.

# SDK de Coleta

> Como integrar o SDK de coleta do Decisionfy no checkout — scripts, ordem de envio, validações e verificação de identidade por biometria.

## SDK de Coleta

O SDK de coleta carrega no navegador os módulos que observam a sessão do usuário (comportamento, dispositivo, geolocalização por IP e grafo) e envia os dados ao Decisionfy no momento do pagamento.

#### Defina a AccessKey e o SessionId

Gere o `sessionId` a cada sessão de checkout e use a `accessKey` da integração do cliente. O `orderId` deve ser único por transação.

```javascript
const accessKey = "SUA_ACCESS_KEY";
const sessionId = window.crypto.randomUUID();
const orderId = "ID_UNICO_DO_PEDIDO";
```

#### Declare os objetos globais

Em TypeScript, inclua a tipagem do `window` para evitar erro de compilação.

```typescript
declare global {
  interface Window {
    BA: any;
    DeviceIntel: any;
    GeoIP: any;
    Graph: any;
    Decisionfy: any;
  }
}
```

#### Carregue os scripts do SDK

Carregue `BA`, `Device`, `GeoIP`, `Graph` e `Decisionfy` com `data-accesskey` e `data-sessionid`. No script `decisionfy.js`, envie também `data-orderid`.

```javascript
useEffect(() => {
  const scriptsToLoad = [
    { id: "ba-script", src: "https://app.decisionfy2-0.credify.com.br/sdk/ba.js", globalVar: "BA" },
    { id: "device-script", src: "https://app.decisionfy2-0.credify.com.br/sdk/device.js", globalVar: "DeviceIntel" },
    { id: "geoip-script", src: "https://app.decisionfy2-0.credify.com.br/sdk/geoIpCheck.js", globalVar: "GeoIP" },
    { id: "graph-script", src: "https://app.decisionfy2-0.credify.com.br/sdk/graphConnect.js", globalVar: "Graph" },
    { id: "decisionfy-script", src: "https://app.decisionfy2-0.credify.com.br/sdk/decisionfy.js", globalVar: "Decisionfy", needsOrderId: true }
  ];

  scriptsToLoad.forEach(({ id, src, globalVar, needsOrderId }) => {
    if (typeof window !== "undefined" && window[globalVar]) {
      delete window[globalVar];
    }

    const oldScript = document.getElementById(id);
    if (oldScript) oldScript.remove();

    const script = document.createElement("script");
    script.id = id;
    script.src = src;
    script.setAttribute("data-accesskey", accessKey);
    script.setAttribute("data-sessionid", sessionId);

    if (needsOrderId) {
      script.setAttribute("data-orderid", orderId);
    }

    script.async = true;
    document.head.appendChild(script);
  });

  return () => {
    if (window.BA && typeof window.BA.stop === "function") {
      window.BA.stop();
    }

    scriptsToLoad.forEach(({ id, globalVar }) => {
      const scriptToRemove = document.getElementById(id);
      if (scriptToRemove) scriptToRemove.remove();
      if (window[globalVar]) delete window[globalVar];
    });
  };
}, [accessKey, sessionId, orderId]);
```

#### Envie a coleta antes de confirmar o pagamento

Ordem recomendada no envio do formulário:

1. `window.BA.stop()`
2. `window.DeviceIntel.send()`
3. `window.GeoIP.send()`
4. `window.Graph.attach({ formData })` e `window.Graph.send()`
5. `window.Decisionfy.send({ action, formData })`

```javascript
const formData = {
  dadosUsuario: {
    nome: "Cliente Teste",
    cpf: "12345678901",
    email: "cliente@email.com"
  },
  dadosPagamento: {
    tipoDePagamento: "PIX",
    valorDaCompra: 199.9
  }
};

if (window.BA) await window.BA.stop();
if (window.DeviceIntel) await window.DeviceIntel.send();
if (window.GeoIP) await window.GeoIP.send();

if (window.Graph) {
  await window.Graph.attach({ formData });
  await window.Graph.send();
}

const response = await window.Decisionfy.send({
  action: "transacao_pix",
  formData,
});

if (!response.ok) {
  console.warn("Falha ao enviar coleta para o Decisionfy", response.status);
}
```

> **Warning**
>
> `orderId` deve ser único por transação e `sessionId` único por sessão de usuário. Em caso de erro no SDK, **não bloqueie a compra** sem necessidade. Sempre limpe os scripts e chame `BA.stop()` ao sair da página.

---

## Verificação de identidade com biometria

Se a `accessKey` tiver a consulta de captura biométrica (**ID 770**) ativa, o motor pode pedir uma selfie ou prova de vida do usuário antes de concluir a decisão. Isso aparece como uma consulta em `WAITING_USER_ACTION` no contexto da decisão. O resultado real (aprovado ou reprovado) chega depois, pelo [Webhook de Decisão](/webhook-de-decisao), independentemente da tela do usuário.

> **Info**
>
> Como a maioria das accessKeys roda em modo `REALTIME`, o `window.Decisionfy.send(...)` devolve a resposta antes de as consultas vinculadas (`bindings`) existirem — elas são criadas logo em seguida, em segundo plano. Por isso não dá para saber pela resposta do `send()` se a captura ficou pendente: é preciso perguntar de novo (polling) até a consulta aparecer ou desistir após alguns segundos.

#### Fluxo via link do Decisionfy (recomendado hoje)

Se o cliente final recebe um link de coleta gerado pelo Decisionfy (`/form?token=...`), isso já funciona automaticamente — não é preciso escrever nada a mais. A própria página faz o polling e carrega o `capture.js` sozinha quando necessário.

```text
GET /api/collect-link/consult-status/:token?consultaId=770
-> { "found": true, "status": "WAITING_USER_ACTION", "bindingId": 920 }
```

O `token` é o mesmo token assinado do link de coleta e funciona como credencial de leitura, sem precisar de JWT de administrador.

#### Embutindo diretamente no seu checkout

Quando a consulta da captura estiver pendente, injete o `capture.js` com o `bindingId` retornado. Ele renderiza a interface de captura sobre a sua página.

```html
<script
  src="https://back.decisionfy2-0.credify.com.br/sdk/capture.js"
  data-accesskey="SUA_ACCESS_KEY"
  data-orderid="ID_DO_PEDIDO"
  data-bindingid="920"
></script>
```

O script dispara um evento com a marca do Decisionfy, para você reagir na sua interface (por exemplo, fechar um modal de espera). O resultado que vale para a decisão continua vindo pelo webhook, não por esse evento.

```javascript
window.addEventListener("decisionfy:capture", (event) => {
  const { event: type } = event.detail;

  if (type === "finish") {
    // usuario concluiu a captura na tela do widget
  }

  if (type === "close" || type === "timeout" || type === "error") {
    // usuario cancelou, deu timeout ou o widget falhou ao iniciar
  }
});
```

> **Warning**
>
> Hoje o polling de status só tem endpoint público para o fluxo de link do Decisionfy. Para embutir direto no seu checkout, sem passar pelo link, fale com o time da Credify — será necessário um mecanismo de status equivalente escopado por `accessKey` e `orderId`.