Retrieve Assets From Card Details

This guide outlines how to securely integrate with Spinwheel’s Credit Card Brand Asset endpoint to retrieve the card program name and artwork by providing credit card metadata.

Overview

❗️

Encryption Required

Due to the nature of the payload, the value provided as creditCardNumberEncrypted must be encrypted with our public key before making requests to the credit card brand API. This ensures end-to-end encryption, with only Spinwheel able to decrypt the value using our private key.

The full API reference can be found here: Retrieve Credit Card Brand.

Encryption Steps

1. Retrieve Spinwheel's public key

The sandbox key can be found here: sandbox-public-v1.pem

2. Encrypt the credit card number

Use RSA with OAEP padding (RSA-OAEP with SHA-256) to encrypt the raw card number string.

Code Examples

const fs = require('fs');
const crypto = require('crypto');

// Load Spinwheel's public key
const publicKey = fs.readFileSync('./spinwheel_public.pem', 'utf8');
const cardNumber = '4111111111111111';

// Encrypt using the crypto module from node
const encryptedBuffer = crypto.publicEncrypt(
  {
    key: publicKey,
    padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
    oaepHash: 'sha256',
  },
  Buffer.from(cardNumber, 'utf8')
);

// Encode to base64 for sending in JSON
const encryptedBase64 = encryptedBuffer.toString('base64');

// Use this as the cardNumber in your API request
console.log(encryptedBase64);
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
import base64

# Load Spinwheel's public key
with open('./spinwheel_public.pem', 'rb') as f:
    public_key = serialization.load_pem_public_key(f.read())

card_number = '4111111111111111'

# Encrypt using RSA OAEP with SHA-256
encrypted = public_key.encrypt(
    card_number.encode('utf-8'),
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Encode to base64 for sending in JSON
encrypted_base64 = base64.b64encode(encrypted).decode('utf-8')

# Use this as the cardNumber in your API request
print(encrypted_base64)

require 'openssl'
require 'base64'

# Load Spinwheel's public key
public_key = OpenSSL::PKey::RSA.new(File.read('./spinwheel_public.pem'))

card_number = '4111111111111111'

# Encrypt using RSA with OAEP and SHA-256
encrypted = public_key.public_encrypt(
  card_number,
  OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
)

# Encode to base64 for sending in JSON
encrypted_base64 = Base64.strict_encode64(encrypted)

# Use this as the cardNumber in your API request
puts encrypted_base64

This encryptedBase64 string should be passed as the value of the creditCardNumberEncrypted field in your API request.

3. Send the encrypted payload

Example curl request:

curl --request POST \
  --url https://secure-sandbox-api.spinwheel.io/v1/creditCards/brands \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --header 'authorization: Bearer <Your access token>' \
  --data '
{
  "extUserId": "user-123456",
  "creditCards": [
    {
      "extCreditCardId": "147500249-1098-1221-2168-6122859797551",
      "creditCardNumberEncrypted": "<Encrypted card number>",
      "accountOriginationDate": "2024-03-12",
      "liabilitySubtype": "FlexibleSpendingCreditCard",
      "creditor": {
        "originalName": "JPMCB CARD SERVICES",
        "address": {
          "addressLine1": "123 Main Street",
          "city": "New York",
          "state": "NY",
          "zip": "10001"
        }
      }
    }
  ]
}
'

Replace <BASE64_ENCRYPTED_CARD_NUMBER> with the actual base64-encoded encrypted string.

Complete Encryption Example

You can use the following test card number and retrieve the sandbox key below, to verify your encryption logic:

Expected encrypted output:

WTFCOX/Nfibo7kpEITwIuKjEIMR7kLo/6iiOdpnJHdU8SeH2IvSG/cCcIuLcXuH89F6XWwCzyoqX55vABN4Jdi1c+o+0Q8+JxSPakVVyr7FwohffBMD2UbH7vYCxQrNZr/S2eAH0KxeEj7+go1qA94ons7GKpDjnMtIR9vJ0AEcOKRaUYWdWFdJxtpZ9MfplIiPrDFJqJyb52N80Oy34l3J9z9Mr6MrpWqQ5gbONcHYY+xIoOMYj8HKUJCtlpBUEzJR2awc6JmKAPeeKRaETt4QTSa4RrXDlqmJG/ZruRRruY8YWF2UMYZKw0J7d0zP8SX4n0jz8UEwT6G66Gf85lw==

🚧

Verifying output

Because RSA-OAEP encryption uses random padding, encrypting the same card number multiple times with the same key will produce different encrypted outputs. This is expected and improves security by preventing ciphertext pattern attacks.

Request to Spinwheel:

curl --request POST \
  --url https://secure-sandbox-api.spinwheel.io/v1/creditCards/brands \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --header 'authorization: Bearer <Your access token>' \
  --data '
{
  "extUserId": "user-123456",
  "creditCards": [
    {
      "extCreditCardId": "147500249-1098-1221-2168-6122859797551",
      "creditCardNumberEncrypted": "WTFCOX/Nfibo7kpEITwIuKjEIMR7kLo/6iiOdpnJHdU8SeH2IvSG/cCcIuLcXuH89F6XWwCzyoqX55vABN4Jdi1c+o+0Q8+JxSPakVVyr7FwohffBMD2UbH7vYCxQrNZr/S2eAH0KxeEj7+go1qA94ons7GKpDjnMtIR9vJ0AEcOKRaUYWdWFdJxtpZ9MfplIiPrDFJqJyb52N80Oy34l3J9z9Mr6MrpWqQ5gbONcHYY+xIoOMYj8HKUJCtlpBUEzJR2awc6JmKAPeeKRaETt4QTSa4RrXDlqmJG/ZruRRruY8YWF2UMYZKw0J7d0zP8SX4n0jz8UEwT6G66Gf85lw==",
      "accountOriginationDate": "2024-03-12",
      "liabilitySubtype": "FlexibleSpendingCreditCard",
      "creditor": {
        "originalName": "JPMCB CARD SERVICES",
        "address": {
          "addressLine1": "123 Main Street",
          "city": "New York",
          "state": "NY",
          "zip": "10001"
        }
      }
    }
  ]
}
'

Key Rotation

Spinwheel may periodically rotate its public key. When this happens:

  • We will notify you in advance
  • You'll be able to download the new public key from the same location
  • A grace period may be supported during which both keys are accepted

Integrating with our Sandbox Environment

We have set up a handful of test cards that you can use as you build out your integration. The relevant details are as follows:

Test card numberExpected result
4147202097111111Chase Sapphire Preferred
5156769324111111Capital One Savor MasterCard
4433905000111111Summit Credit Union Platinum Credit Card
5466801038111111MyLowe's Rewards Credit Card
4111111111111111CREDIT_CARD_NOT_SUPPORTED
9111111111111111INVALID_CARD_NUMBER
5111111111111111UNKNOWN_ERROR