Integração com React

Adicione coleta de dados de cartão compatível com PCI e tokenização ao seu app React com o Tokeflow Bridge SDK — TokeflowProvider, hooks e componentes de elementos seguros.

O Tokeflow Bridge SDK fornece bindings React de primeira classe para que você possa coletar dados de cartão, expor as capacidades do Merchant e tokenizar detalhes de pagamento sem manipular números de cartão brutos. Os dados de cartão são coletados dentro de iframes isolados e cross-origin, criptografados no navegador e nunca chegam aos seus servidores — seus componentes React só veem referências de token.

Esta página cobre a camada React: o TokeflowProvider, os hooks, os componentes de elementos e um formulário de pagamento completo e pronto para TypeScript.

Os bindings React são um wrapper fino sobre o bridge central. Tudo o que você pode fazer com o SDK vanilla está disponível aqui — o provider gerencia uma única instância de bridge e os hooks expõem seu estado à sua árvore de componentes.

Como tudo se encaixa

Seu app React coleta os detalhes do cartão em campos seguros, os tokeniza no navegador e envia apenas o tokenId resultante para o seu backend. Seu backend então usa sua chave secreta para criar a transação na API Tokeflow.

Use uma chave pública (pk_live_… / pk_test_…) no código do navegador. Chaves secretas (sk_*) são apenas para o lado do servidor e nunca devem aparecer em bundles do lado do cliente. Consulte Ambientes e chaves.

Instalação

npm install @tokeflow_com/bridge-js
# or: yarn add @tokeflow_com/bridge-js
# or: pnpm add @tokeflow_com/bridge-js

Os bindings React ficam em uma exportação de subcaminho dedicada:

import {
  TokeflowProvider,
  useTokeflow,
  CardElement,
} from '@tokeflow_com/bridge-js/react';

Os tipos centrais e as classes de erro vêm da exportação raiz:

import { TokeflowError, TokeflowErrorCode } from '@tokeflow_com/bridge-js';

Configuração do provider

Envolva a parte da sua árvore que precisa de pagamentos em um TokeflowProvider. O provider cria e inicializa uma única instância de bridge (que gera uma sessão de navegador e carrega o runtime de elementos seguros) e a compartilha via contexto do React.

import { TokeflowProvider } from '@tokeflow_com/bridge-js/react';

export default function App() {
  return (
    <TokeflowProvider
      config={{
        publicKey: 'pk_test_your_public_key',
        locale: 'pt-BR',
        onError: (error) => console.error(error.code, error.message),
      }}
    >
      <YourApp />
    </TokeflowProvider>
  );
}

Configuração do provider

A prop config aceita a configuração completa do bridge. As opções mais relevantes para um app React:

FieldTypeRequiredDescription
publicKeystringSimSua chave pública Tokeflow (pk_test_* ou pk_live_*).
environment'sandbox' | 'production'NãoAmbiente da API. Detectado automaticamente a partir da chave por padrão.
checkoutSessionIdstringNãoVincula o bridge a uma checkout session criada no backend (cks_…). Obrigatório para useCheckout.
localeTokeflowLocaleNãoLocale padrão para cada elemento. O padrão é 'en'.
translationsPartial<TokeflowTranslations>NãoSobrescreve as strings de tradução integradas.
elementOptions{ style?: ElementStyle; fonts?: string[] }NãoEstilização e fontes padrão aplicadas a cada elemento.
autoRefreshSessionbooleanNãoRenova a sessão antes que ela expire. O padrão é true.
timeoutnumberNãoTimeout da requisição em ms. O padrão é 30000.
onSessionCreated(session: Session) => voidNãoChamado quando uma sessão é criada.
onSessionExpired() => voidNãoChamado quando a sessão expira.
onError(error: TokeflowError) => voidNãoManipulador de erros global.

Monte o provider o mais alto na sua árvore que fizer sentido (por exemplo, em torno da sua rota de checkout), mas não mais alto do que isso — inicializar o bridge gera uma sessão, então não há benefício em criá-lo antes de o usuário chegar a uma superfície de pagamento.

Hooks

Todos os hooks devem ser chamados a partir de um componente renderizado dentro de um TokeflowProvider.

HookReturnsPurpose
useTokeflow(){ tokeflow, session, isReady, error }Acessa a instância do bridge e o estado de prontidão.
useCapabilities()Capabilities | nullCapacidades do Merchant derivadas da sessão.
useSessionSettings()SessionSettings | nullConfigurações de tokenização (por exemplo, bandeiras de cartão permitidas).
useAvailablePaymentMethods()AvailablePaymentMethod[]Métodos que o Merchant habilitou ('cards', 'pix', 'applePay', 'googlePay').
useCheckout(){ context, isLoading, error, refresh }Busca e armazena em cache o contexto de checkout vinculado.

useTokeflow

O hook principal. Condicione sua UI ao isReady antes de tocar no bridge e exiba error se a inicialização falhar.

import { useTokeflow } from '@tokeflow_com/bridge-js/react';

function PaymentForm() {
  const { tokeflow, session, isReady, error } = useTokeflow();

  if (error) return <div role="alert">Error: {error.message}</div>;
  if (!isReady) return <div>Loading payment form…</div>;

  // `tokeflow` is the initialized bridge instance.
  return <p>Session {session?.id} is ready.</p>;
}
FieldTypeDescription
tokeflowTokeflowBridge | nullA instância do bridge. null até o provider inicializar.
sessionSession | nullA sessão de navegador atual.
isReadybooleantrue assim que init() for resolvido e os elementos puderem ser montados.
errorTokeflowError | nullErro de inicialização, se houver.

useCapabilities e useSessionSettings

Leia as capacidades do Merchant e as configurações de tokenização ativas (como as bandeiras de cartão permitidas) para conduzir uma UI condicional.

import { useCapabilities, useSessionSettings } from '@tokeflow_com/bridge-js/react';

function CardBrands() {
  const capabilities = useCapabilities();
  const settings = useSessionSettings();

  if (!settings) return null;

  return (
    <ul>
      {settings.allowedCardBrands?.map((brand) => (
        <li key={brand}>{brand}</li>
      ))}
    </ul>
  );
}

Ambos os hooks retornam null até que a sessão esteja disponível.

useAvailablePaymentMethods

Renderize apenas os métodos de pagamento que o Merchant habilitou.

import { useAvailablePaymentMethods } from '@tokeflow_com/bridge-js/react';

function MethodPicker() {
  const methods = useAvailablePaymentMethods(); // ('cards' | 'pix' | 'boleto' | 'applePay' | 'googlePay')[]

  return (
    <div>
      {methods.includes('cards') && <CardForm />}
      {methods.includes('pix') && <PixForm />}
      {methods.includes('boleto') && <BoletoForm />}
      {methods.includes('applePay') && <ApplePayButton />}
    </div>
  );
}

AvailablePaymentMethod inclui 'boleto' a partir do SDK 2.8.0. Um Record<AvailablePaymentMethod, …> ou um switch exaustivo sobre ele precisa de um case para boleto.

useCheckout

Quando o provider é configurado com um checkoutSessionId, o useCheckout busca e armazena em cache o contexto de checkout — os itens precificados, a moeda selecionada, os métodos de pagamento disponíveis do Merchant e os instrumentos salvos do cliente.

import { useCheckout } from '@tokeflow_com/bridge-js/react';

function CheckoutSummary() {
  const { context, isLoading, error, refresh } = useCheckout();

  if (error) return <p role="alert">{error.message}</p>;
  if (isLoading || !context) return <p>Loading…</p>;

  return (
    <>
      <ul>
        {context.checkout.items.map((item) => (
          <li key={item.id}>
            {item.offerId} — {item.amount} {context.checkout.selectedCurrency}
          </li>
        ))}
      </ul>
      <button onClick={refresh}>Refresh</button>
    </>
  );
}
FieldTypeDescription
contextCheckoutContext | nullO contexto de checkout em cache. null até ser buscado.
isLoadingbooleantrue enquanto o contexto está sendo buscado.
errorTokeflowError | nullErro de busca, se houver.
refresh() => Promise<void>Rebusca depois que seu backend altera o checkout (identifica o cliente, muda itens, etc.).

O useCheckout requer checkoutSessionId na configuração do provider. Sem ele, o hook exibe um erro NO_CHECKOUT_SESSION. Crie a checkout session no seu backend com uma chave secreta e depois passe o id dela (cks_…) ao provider. Consulte Checkout sessions.

Componentes de elementos

Cada elemento renderiza um iframe seguro e cross-origin que coleta uma parte dos dados do cartão (ou de cobrança). O valor criptografado nunca sai do iframe — seu componente recebe apenas eventos de mudança e, por fim, uma referência de token.

React componentDescription
<CardElement>Número + validade + CVC em um único iframe.
<CardNumberElement>Somente o número do cartão.
<CardExpirationElement>Somente a data de validade.
<CardCvcElement>Somente o CVC/CVV.
<CardholderNameElement>Nome no cartão.
<TextElement>Entrada de texto genérica.
<CpfElement>Entrada de CPF brasileiro (usado para PIX).
<AddressLine1Element> / <AddressLine2Element>Linhas do endereço de cobrança.
<CityElement> / <StateElement>Cidade / estado de cobrança.
<PostalCodeElement> / <CountryElement>Código postal / país de cobrança.
<ApplePayButton> / <GooglePayButton>Botões de pagamento de carteira.

Props comuns

Os componentes de elementos aceitam as opções de elemento mais callbacks de eventos amigáveis ao React:

PropTypeDescription
refRef<CardElementRef>Expõe a instância de elemento subjacente via ref.current.element.
idstringId do DOM para o contêiner do elemento.
classNamestringClasse CSS no contêiner.
onReady() => voidDispara quando o campo seguro está pronto.
onChange(e: ElementChangeEvent) => voidDispara a cada mudança de entrada (complete, empty, error, …).
onFocus / onBlur() => voidCiclo de vida de foco.
onError(e) => voidErro no nível do elemento.

O padrão .element do ref

Este é o idioma React fundamental: cada componente de elemento encaminha um ref cuja propriedade .element é a instância de elemento subjacente do bridge. Você passa essa instância — não o componente React — para tokenize().

import { useRef } from 'react';
import { CardElement, CardElementRef } from '@tokeflow_com/bridge-js/react';

function CombinedCardForm() {
  const cardRef = useRef<CardElementRef>(null);

  return (
    <CardElement
      ref={cardRef}
      id="card"
      onReady={() => console.log('Ready')}
      onChange={(e) => console.log('Complete:', e.complete, 'Error:', e.error?.message)}
      className="my-card-element"
    />
  );
}

// Later, on submit:
//   await tokeflow.cards.tokenize({ card: cardRef.current.element });

Campos combinados vs. separados

Use um único <CardElement> ou divida as entradas entre <CardNumberElement>, <CardExpirationElement> e <CardCvcElement> para controle total do layout.

import { useRef } from 'react';
import {
  CardNumberElement,
  CardExpirationElement,
  CardCvcElement,
  CardNumberElementRef,
  CardExpirationElementRef,
  CardCvcElementRef,
} from '@tokeflow_com/bridge-js/react';

function SplitCardForm() {
  const numberRef = useRef<CardNumberElementRef>(null);
  const expiryRef = useRef<CardExpirationElementRef>(null);
  const cvcRef = useRef<CardCvcElementRef>(null);

  // On submit, pass the underlying instances — note the key is `expiration`:
  //   await tokeflow.cards.tokenize({
  //     cardNumber: numberRef.current.element,
  //     expiration: expiryRef.current.element,
  //     cvc: cvcRef.current.element,
  //   });

  return (
    <>
      <CardNumberElement ref={numberRef} id="number" />
      <CardExpirationElement ref={expiryRef} id="expiry" />
      <CardCvcElement ref={cvcRef} id="cvc" />
    </>
  );
}

Com elementos separados, a chave de validade é expiration (não expirationDate). Com o elemento combinado você passa uma única chave card.

Tokenização

tokeflow.cards.tokenize(input, options?) criptografa os dados de cartão coletados e resolve para um CardToken. Envie apenas token.tokenId para o seu backend — nunca qualquer campo de cartão bruto.

const token = await tokeflow.cards.tokenize({
  card: cardRef.current.element,
});
// token.tokenId -> 'tok_…'

O formato do token:

interface CardToken {
  tokenId: string;       // your Tokeflow token reference (tok_…)
  type: 'card';
  brand: string;         // 'visa', 'mastercard', etc.
  last4: string;         // last 4 digits
  expiryMonth: string;   // e.g. '12'
  expiryYear: string;    // e.g. '2029'
  bin?: string;          // bank identification number (optional)
  createdAt?: string;    // ISO 8601 timestamp (optional)
}

Você pode anexar metadados no momento da tokenização:

const token = await tokeflow.cards.tokenize(
  { card: cardRef.current.element },
  { metadata: { cartId: 'cart_123' } }
);

Exemplo de formulário de pagamento completo

Um formulário completo e amigável ao TypeScript com controle de prontidão, validação inline, estado de carregamento e um POST para o seu backend (que então cria a transação com sua chave secreta).

import React, { useRef, useState, FormEvent } from 'react';
import {
  TokeflowProvider,
  useTokeflow,
  CardElement,
  CardElementRef,
} from '@tokeflow_com/bridge-js/react';
import { TokeflowError } from '@tokeflow_com/bridge-js';

function PaymentForm() {
  const { tokeflow, isReady } = useTokeflow();
  const cardRef = useRef<CardElementRef>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    if (!tokeflow || !cardRef.current?.element) return;

    setLoading(true);
    setError(null);

    try {
      // 1. Tokenize in the browser — raw card data never reaches your servers.
      const token = await tokeflow.cards.tokenize({
        card: cardRef.current.element,
      });

      // 2. Send ONLY the token reference to your backend.
      const res = await fetch('/api/payments', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ tokenId: token.tokenId }),
      });

      if (!res.ok) throw new Error('Payment could not be completed.');

      alert('Payment successful!');
    } catch (err) {
      if (err instanceof TokeflowError) {
        // Field-level error from the secure element / tokenization.
        setError(err.message);
      } else {
        setError(err instanceof Error ? err.message : 'Unexpected error.');
      }
    } finally {
      setLoading(false);
    }
  };

  if (!isReady) return <div>Loading payment form…</div>;

  return (
    <form onSubmit={handleSubmit}>
      <div className="form-group">
        <label htmlFor="card-element">Card details</label>
        <CardElement
          ref={cardRef}
          id="card-element"
          onChange={(e) => setError(e.error?.message ?? null)}
        />
      </div>

      {error && (
        <div className="error" role="alert">
          {error}
        </div>
      )}

      <button type="submit" disabled={loading}>
        {loading ? 'Processing…' : 'Pay now'}
      </button>
    </form>
  );
}

export default function App() {
  return (
    <TokeflowProvider config={{ publicKey: 'pk_test_your_public_key' }}>
      <PaymentForm />
    </TokeflowProvider>
  );
}

No servidor, seu manipulador /api/payments recebe o tokenId e cria a cobrança com sua chave secreta:

curl -X POST https://api.tokeflow.com/api/v1/transactions \
  -H "Authorization: Bearer sk_live_mer_your_secret_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f1d9c2e-7a3b-4c8e-9f21-0a1b2c3d4e5f" \
  -d '{
    "amount": 9900,
    "currency": "BRL",
    "payment_method": "credit_card",
    "card_ciphertext_id": "tok_8f3c2a1b"
  }'
{
  "success": true,
  "data": {
    "id": "tx_7c9a1f2b",
    "status": "authorized",
    "amount": 9900,
    "currency": "BRL",
    "payment_method": "credit_card",
    "created_at": "2026-01-15T12:30:00.000Z"
  },
  "request_id": "req_8f3c2a1b",
  "timestamp": "2026-01-15T12:30:00.000Z"
}

Nunca chame a API Tokeflow diretamente do navegador com uma chave secreta. O navegador tokeniza; seu servidor cobra. Consulte Autenticação.

Tratamento de erros

A tokenização e as operações de elemento rejeitam com um TokeflowError. Ramifique com base em seu code legível por máquina (um TokeflowErrorCode) para renderizar mensagens amigáveis.

import { TokeflowError, TokeflowErrorCode } from '@tokeflow_com/bridge-js';

try {
  const token = await tokeflow.cards.tokenize({ card: cardRef.current.element });
} catch (err) {
  if (err instanceof TokeflowError) {
    switch (err.code) {
      case TokeflowErrorCode.INVALID_CARD:
        setError('Please check your card number.');
        break;
      case TokeflowErrorCode.EXPIRED_CARD:
        setError('This card has expired.');
        break;
      case TokeflowErrorCode.ELEMENT_INCOMPLETE:
        setError('Please complete all card fields.');
        break;
      case TokeflowErrorCode.UNSUPPORTED_CARD_BRAND:
        setError('This card brand is not supported.');
        break;
      case TokeflowErrorCode.NETWORK_ERROR:
        setError('Network error. Please try again.');
        break;
      default:
        setError(err.message);
    }
    console.log('code:', err.code, 'requestId:', err.requestId);
  }
}

Códigos comuns que você tratará em um formulário React: ELEMENT_INCOMPLETE, ELEMENT_INVALID, INVALID_CARD, EXPIRED_CARD, UNSUPPORTED_CARD_BRAND, TOKENIZATION_FAILED, NETWORK_ERROR, RATE_LIMITED e SERVER_ERROR. O TokeflowError também expõe httpStatus?, requestId? e details? para diagnósticos.

Defina um manipulador onError global na configuração do provider para encaminhar erros (code, message, requestId) para o seu próprio serviço de logging em um único lugar.

<BoletoInstructions>

Renderiza as payment_instructions de uma cobrança de boleto (SDK 2.8.0+): a linha digitável agrupada como o banco a imprime, um botão de copiar, a data de vencimento e um link "Abrir boleto" para o boleto — exibido apenas para uma URL https.

import { BoletoInstructions } from '@tokeflow_com/bridge-js/react';

<BoletoInstructions
  instructions={paymentInstructions}  // from your server; type: 'boleto'
  locale="pt-BR"                      // default; or 'en'
  onCopy={() => track('boleto_copied')}
/>

Ele não traz estilos: estilize as classes tokeflow-boleto__*. Para PIX, renderize qr_code_text (copia e cola) e qr_code_url você mesmo. Os formatos das instruções são exportados como PixInstructions e BoletoInstructions (no entry de React, BoletoInstructionsData).

A partir do SDK 2.8.1, o entry de React importa o core em vez de embutir sua própria cópia, então err instanceof TokeflowError funciona para erros lançados pelo TokeflowProvider e o bundle de React fica bem menor. Atualize se você usa os dois entries.

Suporte a TypeScript

O SDK fornece definições de tipo completas. Os tipos de ref específicos do React vêm do subcaminho /react:

import type {
  CardElementRef,
  CardNumberElementRef,
  CardExpirationElementRef,
  CardCvcElementRef,
} from '@tokeflow_com/bridge-js/react';

import type {
  Session,
  CardToken,
  TokenizeOptions,
  ElementStyle,
  ElementState,
  ElementChangeEvent,
  CardElementOptions,
  CheckoutContext,
} from '@tokeflow_com/bridge-js';

Próximos passos

Nesta página