<!-- Source: https://docs.infraio.xyz/pt-BR/sdks/javascript -->
<!-- Last updated: 2026-10-04 -->

# SDK JavaScript / Navegador

`@lartech/infraio-checkout-js` é o único SDK que a gente publica
hoje. Roda no navegador e abre o nosso checkout hospedado. Ainda não
há SDK de backend. Chame a API diretamente; o
[Início rápido](https://docs.infraio.xyz/pt-BR/get-started/quickstart) inclui um helper de
assinatura HMAC.

- Versão atual: `0.1.1-beta.17` (pré-1.0; espere pequenas quebras)
- Formatos: **ESM** (`index.js`), **CJS** (`index.cjs`), **IIFE** (`index.global.js`)
- Tipos embutidos (`index.d.ts`)
- Zero dependências de runtime — sem React, jQuery ou outras deps

> **Note:**
>
> **Não existe ponto de entrada do lado do servidor.** Helpers de
> verificação de assinatura para webhooks não vêm embutidos —
> implemente você mesmo com `crypto` (a [página de verificação de
> assinatura](https://docs.infraio.xyz/pt-BR/webhooks/signature-verification) tem código
> pronto para copiar e colar em 4 linguagens).

## Instalação

**npm**

```bash
npm install @lartech/infraio-checkout-js
```

**pnpm**

```bash
pnpm add @lartech/infraio-checkout-js
```

**yarn**

```bash
yarn add @lartech/infraio-checkout-js
```

**bun**

```bash
bun add @lartech/infraio-checkout-js
```

**CDN**

```html
<script src="https://unpkg.com/@lartech/infraio-checkout-js/dist/index.global.js"></script>
<script>
  const sdk = await InfraIo.loadInfraIo("pk_live_yourkeyhere");
  sdk.checkout({ sessionId, checkoutUrl });
</script>
```

## `loadInfraIo(publicKey, options?)`

Retorna uma `Promise<InfraIoInstance>`.

```ts
import { loadInfraIo } from "@lartech/infraio-checkout-js";

const sdk = await loadInfraIo("pk_live_yourkeyhere", {
  // Opcional. Sobrescreva só quando apontar para um ambiente não-prod.
  checkoutUrl: "https://checkout-dev.infraio.xyz",
});
```

| Param | Tipo | Obrigatório | Notas |
| --- | --- | --- | --- |
| `publicKey` | `string` | ✓ | Precisa combinar com `pk_(live\|test)_…` |
| `options.checkoutUrl` | `string` | — | Sobrescreve a URL base do checkout. Padrão: `https://checkout.infraio.xyz`. A página de checkout se conecta automaticamente à API correspondente. |

## `sdk.checkout({ … })`

Abre o checkout hospedado. Retorna `void` (use callbacks para
estado).

| Campo | Tipo | Obrigatório | Notas |
| --- | --- | --- | --- |
| `sessionId` | `string` | ✓ | `session_key` retornado por `POST /b2b/v1/checkout-sessions/quick` |
| `checkoutUrl` | `string` | — | URL completa retornada pelo mesmo endpoint. Se omitida, o SDK constrói a partir do `checkoutUrl` de `loadInfraIo()` (ou do padrão) + `sessionId` |
| `mode` | `"popup" \| "redirect" \| "embed"` | — | Padrão `"popup"` |
| `container` | `string \| HTMLElement` | só embed | Seletor CSS ou elemento do DOM onde o iframe é montado |
| `width` | `number` | — | Só popup. Padrão `560`. Limitado a `[320, 1280]` |
| `height` | `number` | — | Só popup. Padrão `780`. Limitado a `[400, 1000]` |
| `timeoutMs` | `number` | — | Só popup. Timeout de carregamento do iframe. Padrão `30000`. Passe `0` para desativar |
| `locale` | `string` | — | Tag BCP-47 encaminhada como `?locale=` para a página de checkout (`en`, `vi`, `ja`, `ko`, `es`, `pt-BR`, `ru`, `tr`, `zh-CN`, `zh-TW`) |
| `hideSummary` | `boolean` | — | Esconde a coluna de resumo do pedido. Padrão `false` |
| `hideHeader` | `boolean` | — | Esconde o header InfraIO Pay e o botão embutido de wallet-connect. Padrão `false`. Combine com `walletAddress` para white-label completo |
| `walletAddress` | `string` | — | Pré-conecta uma carteira do comprador. Requer `onSignRequest` |
| `walletChainId` | `number` | — | EVM chain ID para a carteira pré-conectada |
| `onReady` | `() => void` | — | Dispara uma vez que o iframe está interativo. Só popup/embed |
| `onSignRequest` | `(req: { method: string; params: unknown[] }) => Promise<string>` | quando `walletAddress` está set | O SDK faz proxy das RPCs de carteira para o seu handler; retorne o hex assinado |
| `onSuccess` | `({ sessionId }) => void` | — | Dispara em pagamento bem-sucedido. **Não é oficial — o webhook é** |
| `onCancel` | `() => void` | — | Dispara quando o comprador fecha o popup/embed sem pagar |
| `onError` | `(err: InfraIoError) => void` | — | Dispara em falha de carregamento do iframe (modos popup + embed). Argumentos inválidos são lançados de forma síncrona, **não** entregues aqui. O modo redirect não tem superfície de erro em runtime — a falha é observada na página redirecionada. |

> **Warning:**
>
> `onSuccess` **não** é oficial. Pode disparar mesmo quando o
> webhook depois determina que o pagamento falhou (reorgs de
> testnet, timing do lado do comprador). Use só para UX (mostrar
> "Obrigado!", redirecionar). Sempre confirme via webhook antes de
> cumprir a entrega.

## `sdk.close()`

Descarta programaticamente um popup ou embed aberto. No-op para o
modo redirect.

```ts
sdk.checkout({ sessionId, mode: "popup", /* … */ });
// depois, por exemplo, quando o usuário navega para longe
sdk.close();
```

## `sdk.openRefundRequest({ … })`

Abre o **formulário hospedado de pedido de reembolso** para um
token de uso único que o seu backend criou via
`POST /b2b/v1/merchants/{merchant_id}/refund-requests`. O comprador
preenche o endereço de destino do reembolso + motivo + (opcional)
metadata na nossa página; a sua página só cuida do ciclo de
abertura/fechamento. Retorna uma **função `close()`** — chame para
descartar programaticamente o popup ou destacar o iframe de embed.
No modo redirect a função retornada é no-op.

> **Note:**
>
> O formulário vive em
> `https://checkout.infraio.xyz/refund-request/:token`. Este método
> só envelopa essa URL num popup / redirect / embed para que o
> comprador nunca saia do seu domínio (em popup / embed) ou volte
> para ele automaticamente (em redirect). O endpoint que o seu
> backend chama para criar o token é
> `POST /b2b/v1/merchants/{merchant_id}/refund-requests` — assinado
> com HMAC pela sua chave secreta, mesma auth do resto da
> superfície B2B. Veja
> [Conceitos → Reembolsos](https://docs.infraio.xyz/pt-BR/concepts/refunds#criacao-via-api-b2b).

```ts
import { loadInfraIo } from "@lartech/infraio-checkout-js";

const sdk = await loadInfraIo("pk_live_yourkeyhere");

// Cria o token no servidor e entrega para o SDK no navegador.
const { token } = await fetch("/api/mint-refund-token", { method: "POST" }).then(r => r.json());

const close = sdk.openRefundRequest({
  token,
  mode: "popup",
  onSuccess: ({ linkToken, refundId }) => {
    // Comprador submeteu o formulário.
    // linkToken → página de status /r/:linkToken (compartilhe com o comprador).
    // refundId  → use com a API B2B para aprovar / rejeitar.
    window.location.href = `/r/${linkToken}`;
  },
  onCancel: () => { /* comprador fechou sem enviar */ },
});

// Descarte programaticamente o popup depois, se precisar:
// close();
```

| Campo | Tipo | Obrigatório | Notas |
| --- | --- | --- | --- |
| `token` | `string` | ✓ | O token `rfqt_…` retornado por `POST /b2b/v1/merchants/{merchant_id}/refund-requests` |
| `mode` | `"popup" \| "redirect" \| "embed"` | — | Padrão `"popup"`. Mesma semântica de superfície do `sdk.checkout()` — veja [Notas sobre os modos](#notas-sobre-os-modos) |
| `container` | `string \| HTMLElement` | só embed | Seletor CSS ou elemento do DOM onde o iframe é montado |
| `locale` | `string` | — | Tag BCP-47 encaminhada como `?locale=` (`en`, `vi`, `ja`, `ko`, `es`, `pt-BR`, `ru`, `tr`, `zh-CN`, `zh-TW`) |
| `hideHeader` | `boolean` | — | Esconde o header InfraIO Pay dentro do iframe. Em popup/embed o SDK desenha o próprio chrome de modal, então o header da página costuma ser desnecessário. Padrão `false` |
| `hideSummary` | `boolean` | — | Esconde a coluna de Resumo do Pedido, mostrando só o formulário de reembolso. Padrão `false` |
| `walletAddress` | `string` | — | Pré-preenche o campo de carteira de destino (`?wallet_address=`). Deixa um lojista que já conhece a carteira do comprador pular a re-digitação manual |
| `onSuccess` | `(data: { linkToken: string; refundId: string }) => void` | — | Dispara depois que o comprador submete o formulário. `linkToken` → página de status `/r/:linkToken` para compartilhar com o comprador. `refundId` → use com a API B2B para aprovar / rejeitar |
| `onCancel` | `() => void` | — | Dispara quando o comprador fecha o popup/embed sem submeter |
| `onError` | `(err: InfraIoError) => void` | — | Dispara em falha de carregamento do iframe ou args inválidos. Expiração de token / cancelamento é tratado pela página hospedada, não via `onError` |

**Estados de token expostos via `onError`**

Se o comprador abre um token velho, a própria página cuida do
display (renderiza um prompt "Expirado — peça link novo", etc.), e
o SDK **não** dispara `onError` para esses casos — o comprador
está dentro do fluxo do formulário e o seu código não precisa
reagir. `onError` só dispara para coisas em que o seu código pode
agir (argumentos ruins, falha de rede ao carregar o iframe).

> **Warning:**
>
> `openRefundRequest` registra a intenção de reembolso — ele **não**
> move fundos. Depois de `onSuccess`, a linha de reembolso está
> `PENDING` (ou `APPROVED` se a sua config de lojista faz
> auto-aprovação de reembolsos de cliente). Você ainda precisa
> assinar e transmitir a transferência on-chain da carteira do seu
> lojista e depois postar o tx hash em
> `POST /b2b/v1/refunds/:id/submit-tx`. Veja
> [Conceitos → Reembolsos](https://docs.infraio.xyz/pt-BR/concepts/refunds) para o ciclo de
> vida completo.

## Classe de erro

```ts
import { InfraIoError } from "@lartech/infraio-checkout-js";

sdk.checkout({
  sessionId,
  onError: (err: InfraIoError) => {
    switch (err.code) {
      case "invalid_request_error":   /* sessionId / args ruins */ break;
      case "iframe_load_error":       /* iframe falhou em carregar */ break;
      case "iframe_timeout_error":    /* excedeu timeoutMs */ break;
      case "already_open_error":      /* outro checkout já está aberto */ break;
      case "network_error":           /* problema de rede transiente falando com a origem do checkout */ break;
      case "api_error":               /* backend retornou não-2xx para uma chamada emitida pelo SDK */ break;
    }
  },
});
```

`sdk.openRefundRequest()` lança somente `invalid_request_error`
(token / args ausentes ou inválidos), de forma síncrona.
`iframe_load_error` (o iframe de pedido de reembolso falhou em
carregar) é entregue **de forma assíncrona via `onError`**, não
lançado. Ele **não** emite `iframe_timeout_error` nem
`already_open_error` — o popup de pedido de reembolso não tem
load-timeout e permite múltiplos popups concorrentes.

## Notas sobre os modos

### Popup
- Overlay centralizado com um backdrop escuro semi-transparente
- `z-index: 2147483647` (max int32) — fica acima de tudo
- Scroll do body é travado enquanto aberto; restaurado no fechamento
- Botão de fechar pega o foco inicial; Tab é trapeado no popup
- Fechado por: botão de fechar, Escape, clique fora, `sdk.close()`.
  Todos eles chamam `onCancel`
- A página de checkout pode pedir resize via `postMessage` — o SDK
  limita dentro dos limites de `width`/`height`

### Redirect
- Navegação completa via `window.location.href`
- Anexa automaticamente `?return_url=<página-atual>` para que o
  comprador volte ao lugar de onde veio. Se a sua `success_url` /
  `cancel_url` na sessão já cobrem isso, a viagem de ida e volta
  ignora `return_url`

### Embed
- iframe com `allow="payment; clipboard-write"` (diretivas HTML5
  Feature Policy — não o atributo `sandbox`). O iframe é servido
  da origem do checkout, então popups de carteira e escritas no
  clipboard do lado do comprador funcionam sem opt-in adicional.
- Largura do container é 100%; altura faz auto-resize via
  postMessage `INFRAIO_RESIZE`, limitada a `[200, 2000]px`
- Sem isolamento CSS além da fronteira do iframe — os estilos da
  página pai não vazam para dentro
- Sempre conecte `onReady` para você poder esconder o seu próprio
  estado de carregamento quando o checkout fica interativo

## TypeScript

Todos os tipos vêm embutidos. Exports mais úteis:

```ts
import type {
  CheckoutOptions,
  RefundRequestOptions,
  LoadOptions,
  InfraIoInstance,
  InfraIoErrorCode,
} from "@lartech/infraio-checkout-js";
import { loadInfraIo, InfraIoError, VERSION } from "@lartech/infraio-checkout-js";
```

`VERSION` é a string de versão do próprio SDK — útil em bug
reports.
