Para garantir a segurança dos dados sensíveis do cartão, nenhuma informação de cartão deve trafegar ou ser armazenada em texto puro. Neste fluxo, os dados do cartão são tokenizados no cliente utilizando criptografia assimétrica, e apenas o token criptografado é enviado para a API.
A tokenização usa a chave de tokenização, não a chave de API. Ela fica em Financeiro → Integrações, na seção Credenciais de API, e pode ser publicada no navegador. A chave de API é secreta e nunca deve aparecer no front-end.
A plataforma suporta duas formas de tokenização:
1. Via script de tokenização (Front-end) — recomendada para integrações diretas no browser, como checkouts web e aplicações client-side.
2. Via classe PaymentTokenizer (API / Back-end) — recomendada para integrações server-to-server, onde a criptografia ocorre no backend do integrador antes do envio para a API.
O processo de tokenização segue os seguintes passos:
1. Utilize a chave de tokenização da loja.
2. Os dados do cartão são criptografados localmente usando essa chave.
3. O resultado é um token.
4. Esse token é enviado para a API de pagamentos no lugar dos dados do cartão.
Para realizar transações com cartão de crédito, é necessário incluir o token do cartão na requisição.
A geração desse token é simples e deve ser feita no front-end, antes de enviar os dados para a API.
Abaixo está o primeiro passo, que consiste em importar o script oficial de tokenização.
Adicione o script abaixo na sua página HTML. Ele é um módulo ES, então a tag precisa de type="module".
<script type="module" src="https://api.avenpayments.com/v1/scripts"></script>O script registra o tokenizador em window["AvenPay"]. Use-o em outro <script type="module">, colocado depois do primeiro. Os campos do cartão são number, holder, expMonth (dois dígitos, ex: "08"), expYear (quatro dígitos, ex: "2027") e cvv, todos como texto.
<script type="module">
const pk = "CHAVE_DE_TOKENIZACAO";
const tokenizer = window["AvenPay"];
try {
await tokenizer.init(pk);
const token = await tokenizer.encrypt({
number: "5555444433331111",
holder: "John Doe",
expMonth: "08",
expYear: "2027",
cvv: "789",
});
// envie o token para o seu backend
} catch (error) {
// ex.: "INVALID_CVV" "cvv" "CVV must have 3 or 4 digits."
if (error.name === "PaymentError") console.log(error.code, error.field, error.description);
}
</script>O tokenizador faz throw de um PaymentError. O message é o próprio code, então quem já compara error.message continua funcionando.
Campo do erro | O que traz |
|---|---|
| name | Sempre "PaymentError". |
| code | O código da tabela abaixo. Use para decidir o que fazer. |
| description | Texto curto em inglês, para log ou para mostrar ao desenvolvedor. |
| field | O campo do cartão com problema. Vazio quando o erro não é de um campo. |
code | field | Quando acontece | O que fazer |
|---|---|---|---|
| INVALID_TOKENIZATION_KEY | O init recebeu a chave vazia. | Use a chave de tokenização de Financeiro → Integrações. | |
| TOKENIZER_NOT_INITIALIZED | O encrypt foi chamado antes do init. | Chame await init(pk) antes. | |
| INVALID_CARD_HOLDER | holder | Nome do titular vazio. | Peça o nome como está no cartão. |
| INVALID_CARD_NUMBER | number | O número não tem de 13 a 19 dígitos. | Peça ao comprador para conferir o número. |
| INVALID_EXP_MONTH | expMonth | O mês não tem dois dígitos ou está fora de 01 a 12. | Envie de "01" a "12". |
| INVALID_EXP_YEAR | expYear | O ano não tem quatro dígitos. | Envie "2027", não "27". |
| CARD_EXPIRED | expYear | O cartão venceu antes do mês atual. O mês atual ainda vale: em outubro de 2026, 10/2026 passa e 09/2026 não. | Peça outro cartão. |
| INVALID_CVV | cvv | O CVV não tem 3 ou 4 dígitos. | Peça ao comprador para conferir o código de segurança. |
Essa forma é indicada para quem vai integrar via backend (API, workers ou server-to-server) e precisa tokenizar o cartão antes de enviar para a API de pagamentos.
A tokenização continua acontecendo no seu ambiente, usando criptografia assimétrica. Apenas o token é enviado para a plataforma.
1. Utilize a chave de tokenização da loja.
2. Sua aplicação inicializa a classe PaymentTokenizer com essa chave.
3. Os dados do cartão são validados e criptografados localmente.
4. O resultado é um token.
5. Esse token é enviado para a API de pagamentos no lugar dos dados do cartão.
A classe utiliza libsodium para criptografia:
import sodium from "https://cdn.jsdelivr.net/npm/libsodium-wrappers@0.8.0/+esmimport sodium from "https://cdn.jsdelivr.net/npm/libsodium-wrappers@0.8.0/+esm";
type CardDTO = {
number: string;
holder: string;
expMonth: string;
expYear: string;
cvv: string;
};
export class PaymentError extends Error {
code: string;
description: string;
field?: string;
constructor(code: string, description: string, field?: string) {
super(code);
this.name = "PaymentError";
this.code = code;
this.description = description;
this.field = field;
}
}
export class PaymentTokenizer {
tokenizationKey = "";
initialized = false;
async init(pk: string): Promise<void> {
this.assertValidTokenizationKey(pk);
await sodium.ready;
this.tokenizationKey = pk;
this.initialized = true;
}
async encrypt(card: CardDTO): Promise<string> {
if (!this.initialized || !this.tokenizationKey) {
throw new PaymentError("TOKENIZER_NOT_INITIALIZED", "Call init(pk) before encrypt().");
}
const payload = this.buildPayload(card);
const encrypted = sodium.crypto_box_seal(sodium.from_string(JSON.stringify(payload)), sodium.from_base64(this.tokenizationKey));
return sodium.to_base64(encrypted);
}
buildPayload(card: CardDTO): CardDTO {
const number = this.validateCardNumber(card.number);
const holder = this.validateHolder(card.holder);
const expMonth = this.validateMonth(card.expMonth);
return {
number,
holder,
expMonth,
expYear: this.validateYear(card.expYear, expMonth),
cvv: this.validateCvv(card.cvv),
};
}
assertValidTokenizationKey(pk: string) {
if (!pk || typeof pk !== "string" || pk.trim() === "") {
throw new PaymentError("INVALID_TOKENIZATION_KEY", "Tokenization key is missing or invalid. Use the card key from your dashboard.");
}
}
validateHolder(value: string): string {
if (!value?.trim()) {
throw new PaymentError("INVALID_CARD_HOLDER", "Cardholder name is required.", "holder");
}
return value.trim();
}
validateCardNumber(value: string): string {
const number = String(value ?? "").replace(/\D/g, "");
if (!/^\d{13,19}$/.test(number)) {
throw new PaymentError("INVALID_CARD_NUMBER", "Card number must have 13 to 19 digits.", "number");
}
return number;
}
validateMonth(value: string): string {
const monthStr = String(value ?? "").replace(/\D/g, "");
if (!/^\d{2}$/.test(monthStr)) {
throw new PaymentError("INVALID_EXP_MONTH", "Expiration month must be two digits between 01 and 12.", "expMonth");
}
const month = Number(monthStr);
if (month < 1 || month > 12) {
throw new PaymentError("INVALID_EXP_MONTH", "Expiration month must be two digits between 01 and 12.", "expMonth");
}
return monthStr;
}
validateYear(value: string, month: string): string {
const yearStr = String(value ?? "").replace(/\D/g, "");
if (!/^\d{4}$/.test(yearStr)) {
throw new PaymentError("INVALID_EXP_YEAR", "Expiration year must have four digits.", "expYear");
}
const year = Number(yearStr);
const now = new Date();
const currentYear = now.getFullYear();
const isPastYear = year < currentYear;
const isPastMonth = year === currentYear && Number(month) < now.getMonth() + 1;
if (isPastYear || isPastMonth) {
throw new PaymentError("CARD_EXPIRED", "Card is expired.", "expYear");
}
return yearStr;
}
validateCvv(value: string): string {
const cvv = String(value ?? "").replace(/\D/g, "");
if (!/^\d{3,4}$/.test(cvv)) {
throw new PaymentError("INVALID_CVV", "CVV must have 3 or 4 digits.", "cvv");
}
return cvv;
}
}import { PaymentError, PaymentTokenizer } from "./payment-tokenizer";
const pk = "SUA_CHAVE_DE_TOKENIZACAO";
const tokenizer = new PaymentTokenizer();
try {
await tokenizer.init(pk);
const token = await tokenizer.encrypt({
number: "4111111111111111",
holder: "JOHN DOE",
expMonth: "12",
expYear: "2030",
cvv: "123",
});
} catch (error) {
if (error instanceof PaymentError && error.code === "CARD_EXPIRED") {
// peça outro cartão
}
}