Cofre

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

  1. Pegue encryptionKey da intenção (keyId + chave pública em JWK), ou de GET {vaultUrl}/keys.
  2. Gere, por chamada, uma chave AES de 32 bytes e um IV de 12 bytes aleatórios.
  3. 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.
  4. 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 com withHash('sha256')->withMGFHash('sha256')).
  5. Codifique cada campo em base64 padrão com = de padding (não base64url, não hex).
  6. 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.

POST
/tokenize
ticketstring

Veio em cardTokenization.ticket.

Lengthlength <= 4096
encryptedCardEncryptedCard

Envelope 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."
}