Tokenizar cartão (cofre)
Recebe o cartão cifrado mais o ticket da intenção, tokeniza na adquirente e devolve
um token de uso único. O cofre não guarda o cartão.
Não leva chave de API. O ticket é a autorização: foi emitido pela SwitchPay para
aquela intenção, vale 5 minutos e só uma vez. Corpo máximo: 8 KB.
Como cifrar o cartão
- Pegue
encryptionKeyda intenção (keyId+ chave pública em JWK), ou deGET {vaultUrl}/keys. - Gere, por chamada, uma chave AES de 32 bytes e um IV de 12 bytes aleatórios.
- Cifre o JSON minificado do cartão — campos
number(só dígitos),holderName,expMonth(1–12),expYear(4 dígitos),cvv(texto, 3–4 dígitos) — com AES-256-GCM, sem dado adicional (AAD vazio). Tag de 16 bytes, separada do ciphertext. - Cifre os 32 bytes da chave AES com a chave pública usando RSA-OAEP com SHA-256 no
hash e no MGF1 (Java:
RSA/ECB/OAEPWithSHA-256AndMGF1Padding+MGF1ParameterSpec.SHA256; .NET:RSAEncryptionPadding.OaepSHA256; PHP: phpseclib comwithHash('sha256')->withMGFHash('sha256')). - Codifique cada campo em base64 padrão com
=de padding (não base64url, não hex). - Envie
{ keyId, encryptedKey, iv, ciphertext, tag }.
Biblioteca pronta em JavaScript (Node e navegador) é publicada junto com o cofre. No sandbox o cofre abre e confere o cartão cifrado igual à produção; só a ida à adquirente é simulada, e o token devolvido é de teste (ver Sandbox).
O que gasta o ticket
Envelope inválido (400) não gasta o ticket — corrija e reenvie com o mesmo ticket.
Ticket aceito e adquirente falhou (502) gasta: crie outra intenção.
Veio em cardTokenization.ticket.
length <= 4096Envelope do cartão cifrado no cliente. Todos os binários em base64 padrão (com =), não base64url.
Response Body
curl -X POST "https://api.sandbox.switchpay.app.br/tokenize" \ -H "Content-Type: application/json" \ -d '{ "ticket": "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImtpZCI6InZhdWx0LWVuYy0yMDI2LTEwIiwiY3R5IjoiSldUIn0..Qm9…(texto opaco, ~1 000 caracteres)", "encryptedCard": { "keyId": "card-2026-10", "encryptedKey": "k3Jv…(384 bytes em base64, 512 caracteres)…==", "iv": "sS7G6k3xQ1mBvYcD", "ciphertext": "9fQ2…(~100 bytes em base64)…", "tag": "Z0t7bqk1yJfJ0mXhqzQ2Lw==" } }'{
"token": "vtk_eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImtpZCI6ImZpbi1lbmMtMjAyNi0xMCIsImN0eSI6IkpXVCJ9..0Ozx…(texto opaco, ~1 400 caracteres)",
"brand": "VISA",
"first4": "4111",
"last4": "1111",
"expiresAt": "2026-10-06T14:05:00.000Z"
}{
"code": "VALIDATION_ERROR",
"message": "Envelope do cartão inválido.",
"details": [
{
"field": "encryptedCard.ciphertext",
"message": "não foi possível decifrar"
}
]
}{
"code": "TICKET_INVALID",
"message": "Ticket inválido."
}{
"code": "RATE_LIMITED",
"message": "Limite de chamadas atingido. Aguarde e tente de novo."
}{
"code": "PROVIDER_ERROR",
"message": "A adquirente não respondeu. Tente novamente mais tarde."
}