Skip to content

Get card information

GET
/card

Retrieve the card profile, encrypted card data, and (optionally) a signature challenge for an authenticated user.

The sessionid header and the scope query parameter are independent and may be used together or separately:

  • Provide sessionid to receive encryptedPan, encryptedCvc, and pin. Without it, only the card profile is returned.
  • Provide scope=siwe or scope=webauthn to receive a challenge to be signed and submitted via PATCH /. siwe and webauthn are mutually exclusive within a single request.

Successful responses include push-provisioning credentials in the provisioning field only when the scope=provisioning query parameter is sent.

Retrieving encrypted card details

  1. Generate a session ID: Encrypt a 32‑character hexadecimal secret (no spaces/dashes) with the provided public RSA key using RSA‑OAEP.
  2. Send the request: Include the encrypted secret in the header sessionid when calling this endpoint.
  3. Decrypt the response: Use the original secret to decrypt encryptedPan, encryptedCvc, and pin (each returned as { data, iv }).

Requesting a signature challenge

Pass scope=siwe to receive a fully formed Sign-In with Ethereum message in challenge, or scope=webauthn to receive the plain authorization statement to be signed by a passkey. The signed result is submitted to PATCH / to bind the card to the user.

Step 1: Generate a sessionid and secret

import crypto from "node:crypto";

function session(): { sessionid: string; secret: string } {
  const secret = crypto.randomUUID().replaceAll("-", "");
  const secretKeyBase64 = Buffer.from(secret, "hex").toString("base64");
  const secretKeyBase64Buffer = Buffer.from(secretKeyBase64, "utf8");
  const secretKeyBase64BufferEncrypted = crypto.publicEncrypt(
    { key: pem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
    secretKeyBase64Buffer,
  );
  return {
    sessionid: secretKeyBase64BufferEncrypted.toString("base64"),
    secret,
  };
}

The sessionid is required to make an API request. The secret will be needed for decryption later.

Step 2: Send the request

Use the sessionid in the header when calling this endpoint.

Step 3: Decrypt the response

Use the secret from Step 1 to decrypt the data.

import crypto from "node:crypto";

function decrypt(base64Secret: string, base64Iv: string, secretKey: string): string {
  const secret = Buffer.from(base64Secret, "base64");
  const iv = Buffer.from(base64Iv, "base64");
  const decipher = crypto.createDecipheriv("aes-128-gcm", Buffer.from(secretKey, "hex"), iv);
  decipher.setAutoPadding(false);
  decipher.setAuthTag(secret.subarray(-16));
  return Buffer.concat([decipher.update(secret.subarray(0, -16)), decipher.final()]).toString("utf8");
}
sessionid
string
scope
Any of:
string
Allowed values: provisioning siwe webauthn

Card information

object
cardId
required
string format: uuid
Example
123e4567-e89b-12d3-a456-426655440000
displayName
required
string
Example
John Doe
encryptedPan
object
data
required
string
iv
required
string
encryptedCvc
object
data
required
string
iv
required
string
expirationMonth
required
string
Example
12
expirationYear
required
string
Example
2025
lastFour
required
string
Example
1234
mode
required
number
0
pin
Any of:
object
data
required
string
iv
required
string
provider
required
Allowed values: panda
Example
panda
status
required
string
Allowed values: ACTIVE FROZEN
Example
ACTIVE
limit
required
object
amount
required
number
frequency
required
string
Allowed values: per24HourPeriod per7DayPeriod per30DayPeriod perYearPeriod allTime perAuthorization
productId
required
string
Allowed values: 408 406 424
Example
408
challenge
string
Example
1a2b3c
provisioning
object
id
required
string
Example
card_abc123
secret
required
string
Example
otp_xyz

Bad request

Any of:
object
code
required
Allowed values: bad request

Forbidden

object
code
required
Allowed values: no panda

Not found

object
code
required
Allowed values: no card