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-jsOs 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:
| Field | Type | Required | Description |
|---|---|---|---|
publicKey | string | Sim | Sua chave pública Tokeflow (pk_test_* ou pk_live_*). |
environment | 'sandbox' | 'production' | Não | Ambiente da API. Detectado automaticamente a partir da chave por padrão. |
checkoutSessionId | string | Não | Vincula o bridge a uma checkout session criada no backend (cks_…). Obrigatório para useCheckout. |
locale | TokeflowLocale | Não | Locale padrão para cada elemento. O padrão é 'en'. |
translations | Partial<TokeflowTranslations> | Não | Sobrescreve as strings de tradução integradas. |
elementOptions | { style?: ElementStyle; fonts?: string[] } | Não | Estilização e fontes padrão aplicadas a cada elemento. |
autoRefreshSession | boolean | Não | Renova a sessão antes que ela expire. O padrão é true. |
timeout | number | Não | Timeout da requisição em ms. O padrão é 30000. |
onSessionCreated | (session: Session) => void | Não | Chamado quando uma sessão é criada. |
onSessionExpired | () => void | Não | Chamado quando a sessão expira. |
onError | (error: TokeflowError) => void | Não | Manipulador 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.
| Hook | Returns | Purpose |
|---|---|---|
useTokeflow() | { tokeflow, session, isReady, error } | Acessa a instância do bridge e o estado de prontidão. |
useCapabilities() | Capabilities | null | Capacidades do Merchant derivadas da sessão. |
useSessionSettings() | SessionSettings | null | Configuraçõ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>;
}| Field | Type | Description |
|---|---|---|
tokeflow | TokeflowBridge | null | A instância do bridge. null até o provider inicializar. |
session | Session | null | A sessão de navegador atual. |
isReady | boolean | true assim que init() for resolvido e os elementos puderem ser montados. |
error | TokeflowError | null | Erro 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>
</>
);
}| Field | Type | Description |
|---|---|---|
context | CheckoutContext | null | O contexto de checkout em cache. null até ser buscado. |
isLoading | boolean | true enquanto o contexto está sendo buscado. |
error | TokeflowError | null | Erro 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 component | Description |
|---|---|
<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:
| Prop | Type | Description |
|---|---|---|
ref | Ref<CardElementRef> | Expõe a instância de elemento subjacente via ref.current.element. |
id | string | Id do DOM para o contêiner do elemento. |
className | string | Classe CSS no contêiner. |
onReady | () => void | Dispara quando o campo seguro está pronto. |
onChange | (e: ElementChangeEvent) => void | Dispara a cada mudança de entrada (complete, empty, error, …). |
onFocus / onBlur | () => void | Ciclo de vida de foco. |
onError | (e) => void | Erro 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
- Autenticação — chaves públicas vs. secretas e como cobrar a partir do seu backend.
- Checkout sessions — dê suporte ao hook
useCheckoutcom uma sessão criada no servidor. - Transações — crie a cobrança a partir do seu backend usando o
tokenId. - Idempotência e limites de taxa — torne suas requisições de cobrança seguras para repetir.