Retrieve a card image with the JS SDK

Render a digital, digital-first, or virtual card image securely in the cardholder's browser without card data touching your servers.

You can display the image of a digital or digital-first debit, prepaid, or virtual card directly in the cardholder's browser using the PCE JavaScript SDK. The SDK collects and renders sensitive card details client-side, so card data never touches your servers. This reduces your liability and keeps your PCI compliance scope small. By default the card's front image renders with the card details masked.

Why use the JS SDK

  • PCI compliance and security: card data is handled securely in the browser, reducing the risk of a data breach.
  • Reduced liability: because card data is never stored on your server, you avoid costly security infrastructure and simplify PCI compliance.

Set up the card renderer

Step 1: Import the SDK

Add the card renderer script to your HTML template. Use the environment that matches your integration.

<!-- Production -->
<script src="https://js.prioritypassport.com/public/card-renderer/card.renderer.js"></script>

<!-- Sandbox -->
<script src="https://js.sandbox.prioritypassport.com/public/card-renderer/card.renderer.js"></script>

Step 2: Construct the token API URL

Build the token URL for the card whose image you want to render.

<baseURL>/v1/customer/id/<customerID>/account/id/<accountID>/<cardType>/id/<cardID>/image/token

Collect these values from your inputs:

AttributeDescription
baseURLPCE API base URL. Sandbox: https://api.sandbox.prioritypassport.com. Production: https://api.prioritypassport.com. Set as the default when creating the SDK instance.
customerIDUnique identifier of the customer.
accountIDUnique identifier of the customer's account.
cardIDUnique identifier of the issued debit, prepaid, or virtual card.
cardTypeType of card. Accepted values: debitCard, prepaidCard, virtualCard.

Call the token API with the Program Manager's secure Bearer token.

🚧

Do not generate the access token from the browser. Doing so exposes your bearer token, which does not expire, and is a security risk. Generate the token server-side and pass only the short-lived image token to the browser.

Step 3: Define the image container

Add an img element where the rendered card image will be displayed. The SDK populates it dynamically.

<div id="image-container">
  <img id="api-image" alt="Rendered card image" />
</div>

Initialize and render the card image

You can also let cardholders copy the full card number (without spaces) to the clipboard with a single click, and position the copy button where you want it.

Step 1: Create a card instance

// Debit or virtual card
const sdk = new VirtualDebitCard();

// Prepaid card
const sdk = new PrepaidCard();

This configures the base URL of the PCE integration API.

Step 2: Construct the token URL and fetch the token

// Debit or virtual card
const debitCardTokenURL = `${baseURL}/v1/customer/${customerIdType}/${customerID}/account/${accountIdType}/${accountID}/${cardType}/${cardIdType}/${cardID}/image/token`;

// Prepaid card
const prepaidCardTokenURL = `${baseURL}/v1/customer/${customerIdType}/${customerID}/issuance/card/${cardIdType}/${cardID}/image/token`;

async function fetchToken(tokenUrl, bearerToken) {
  const response = await fetch(tokenUrl, {
    method: 'GET',
    headers: { 'Authorization': bearerToken }
  });
  if (!response.ok) {
    throw new Error(`Token API returned status: ${response.status}`);
  }
  const data = await response.json();
  return data.token;
}

const imageToken = await fetchToken(tokenURL, bearerToken);

Step 3: Render the card image

Call renderImage() with the token from Step 2 to populate the img element.

sdk.renderImage(customerID, cardID, imageToken, "api-image", "pan-container");
ParameterDescription
customerIDUnique identifier of the customer.
cardIDUnique identifier of the issued card.
imageTokenToken generated in Step 2.
"api-image"Id of the img element defined in the image container.
"pan-container"Id of the element where the copy-card-number button is inserted (optional).

Complete HTML example

The following template shows the full integration, including card-type selection, token fetch, and rendering.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Card token and image rendering</title>
</head>
<body>
  <div class="left-section">
    <h1>Enter card details</h1>

    <div class="radio-group">
      <label><input type="radio" name="cardType" value="debitCard" checked /> Debit card</label>
      <label><input type="radio" name="cardType" value="virtualCard" /> Virtual card</label>
      <label><input type="radio" name="cardType" value="prepaidCard" /> Prepaid card</label>
    </div>

    <label for="baseURL">Base URL</label>
    <input type="text" id="baseURL" placeholder="Enter base URL" />

    <label for="customerID">Customer</label>
    <div class="input-group">
      <select id="customerIdType">
        <option value="id">ID</option>
        <option value="externalId">External ID</option>
      </select>
      <input type="text" id="customerID" placeholder="Enter customer ID" />
    </div>

    <label for="accountID">Account</label>
    <div class="input-group">
      <select id="accountIdType">
        <option value="id">ID</option>
        <option value="externalId">External ID</option>
      </select>
      <input type="text" id="accountID" placeholder="Enter account ID" />
    </div>

    <label for="cardID">Card</label>
    <div class="input-group">
      <select id="cardIdType">
        <option value="id">ID</option>
        <option value="externalId">External ID</option>
      </select>
      <input type="text" id="cardID" placeholder="Enter card ID" />
    </div>

    <label for="token">Token</label>
    <input type="text" id="token" placeholder="Enter token" />

    <label style="margin-top: 16px; display: block;">Copy card number button location</label>
    <div class="radio-group">
      <label><input type="radio" name="panButtonLocation" value="default" checked /> Default</label>
      <label><input type="radio" name="panButtonLocation" value="custom" /> Custom (below the Render Card button)</label>
    </div>

    <button onclick="renderCard()">Render card</button>
    <div id="pan-container"></div>
  </div>

  <div class="right-section">
    <h1>Rendered card image</h1>
    <div id="image-container">
      <img id="api-image" />
    </div>
  </div>

  <script src="https://js.prioritypassport.com/public/card-renderer/card.renderer.js"></script>

  <script>
    document.querySelectorAll('input[name="cardType"]').forEach((radio) => {
      radio.addEventListener("change", function () {
        const cardIdTypeDropdown = document.getElementById("cardIdType");
        const customerIdTypeDropdown = document.getElementById("customerIdType");
        const accountIdTypeDropdown = document.getElementById("accountIdType");
        const accountIdInput = document.getElementById("accountID");
        const accountLabel = document.querySelector('label[for="accountID"]');

        customerIdTypeDropdown.value = "id";
        accountIdTypeDropdown.value = "id";
        cardIdTypeDropdown.value = "id";
        cardIdTypeDropdown.disabled = this.value === "virtualCard";

        if (this.value === "prepaidCard") {
          accountIdTypeDropdown.style.display = "none";
          accountIdInput.style.display = "none";
          accountLabel.style.display = "none";
        } else {
          accountIdTypeDropdown.style.display = "block";
          accountIdInput.style.display = "block";
          accountLabel.style.display = "block";
        }
      });
    });
  </script>

  <script>
    const CardType = Object.freeze({
      DEBIT: "debitCard",
      VIRTUAL: "virtualCard",
      PREPAID: "prepaidCard"
    });

    async function renderCard() {
      const renderButton = document.querySelector("button");
      renderButton.disabled = true;

      const baseURL = document.getElementById("baseURL").value.trim();
      const customerID = document.getElementById("customerID").value;
      const customerIdType = document.getElementById("customerIdType").value;
      const accountID = document.getElementById("accountID").value;
      const accountIdType = document.getElementById("accountIdType").value;
      const cardIdType = document.getElementById("cardIdType").value;
      const cardID = document.getElementById("cardID").value;
      const token = 'Bearer ' + document.getElementById("token").value;
      const cardType = document.querySelector('input[name="cardType"]:checked').value;

      const imageElement = document.getElementById("api-image");
      imageElement.src = "";

      if (!baseURL || !customerID || ((cardType === CardType.DEBIT || cardType === CardType.VIRTUAL) && !accountID) || !cardID || !token) {
        alert("Please fill out all fields.");
        renderButton.disabled = false;
        return;
      }

      const tokenURL = cardType === CardType.PREPAID
        ? `${baseURL}/v1/customer/${customerIdType}/${customerID}/issuance/card/${cardIdType}/${cardID}/image/token`
        : `${baseURL}/v1/customer/${customerIdType}/${customerID}/account/${accountIdType}/${accountID}/${cardType}/${cardIdType}/${cardID}/image/token`;

      try {
        const imageToken = await fetchToken(tokenURL, token);
        if (imageToken) {
          const sdk = cardType === CardType.PREPAID ? new PrepaidCard() : new VirtualDebitCard();
          sdk.setBaseURL(baseURL);
          const customer = customerIdType === 'id' ? new Customer(customerID, null) : new Customer(null, customerID);
          const card = cardIdType === 'id' ? new Card(cardID, null) : new Card(null, cardID);
          const panButtonLocation = document.querySelector('input[name="panButtonLocation"]:checked').value;
          if (panButtonLocation === 'custom') {
            sdk.renderImage(customer, card, imageToken, "api-image", "pan-container");
          } else {
            sdk.renderImage(customer, card, imageToken, "api-image");
          }
        } else {
          alert("Failed to render card. Please check the inputs.");
        }
      } catch (error) {
        console.error("Error rendering card:", error);
        alert("Failed to render card. Please check the inputs.");
      }

      renderButton.disabled = false;
    }

    async function fetchToken(tokenApiUrl, token) {
      const response = await fetch(tokenApiUrl, {
        method: 'GET',
        headers: { 'Authorization': token }
      });
      if (!response.ok) {
        throw new Error(`Token API returned status: ${response.status}`);
      }
      const data = await response.json();
      return data.token;
    }
  </script>
</body>
</html>

Next steps

See also



Did this page help you?
.readme-logo { display: none !important; }