Embedded Card UI

Learn how to embed card details

Handling full card PANs and CVV codes requires that you comply with the Payment Card Industry Data Security Standards (PCI DSS). Some clients choose to reduce their compliance obligations by using our modern embedded card solution documented below.

With our embedded card solution, you create a short-lived embed session each time you want to display a card's PAN, CVV, and expiration details to an end-user. These details are presented via an iframe we provide, and the lithic-embed SDK lets you mount them and track user actions and state changes within it.

A user's browser makes the request directly to api.lithic.com, so card details never touch the API client's servers while full card details are displayed to their end-users.

🚧

The legacy direct-iframe embed URLs (GET /v1/embed/card) are deprecated but still supported. If you are integrated with that approach, see Deprecated Embedded Card UI for its reference.

Getting Started

Step 1: Install the SDK

Install lithic-embed in your frontend project.

# npm
npm install lithic-embed

# bun
bun add lithic-embed

# pnpm
pnpm add lithic-embed

Step 2: Create an embed session

Call Create Card Embed Session from your backend and pass the returned session token to your frontend. Generating the session server-side keeps your API key off the client.

POST https://api.lithic.com/v1/cards/{card_token}/embed
typeThe type of card embed to create. Only CARD_EMBED and PIN_SETTING_EMBED are currently accepted.
target_originCanonical HTTPS origin of the page that will embed the iframe.
expirationUnix timestamp at which the session expires. The value must be in the future and no more than 10 minutes after the request. If omitted, the session expires 10 minutes after the request.
{
    "session": "eyJhb..."
}

Step 3: Mount the card embed

On your frontend, initialize the SDK with the session token from Step 2 and mount the card details into elements on your page.

import LithicEmbed, { Environment } from "lithic-embed";

// Fetch the session token from your backend (see Step 2)
const sessionToken = await fetchSessionToken();
const lithicEmbed = new LithicEmbed(Environment.PRODUCTION);

const cardEmbed = lithicEmbed.card(sessionToken);
await cardEmbed.mount({
  pan: { selector: "#pan" },
  cvv: { selector: "#cvv" },
  expMonth: { selector: "#expMonth" },
  expYear: { selector: "#expYear" },
});

Step 4: Reveal the card details

By default, Lithic embeds are masked with only the PAN showing the last 4 digits. To reveal the card details, call toggleMasking, which fetches and reveals the details for all mounted card embeds.

import { CardDetailsRequestError } from "lithic-embed";

try {
  await cardEmbed.toggleMasking();
} catch (error) {
  if (error instanceof CardDetailsRequestError) {
    // Handle a card-details request failure.
    console.error(error.code);
    console.error(error.requestId);
  }
}

Advanced usage

Mounting an individual field

Use mountPan to mount only the PAN into a single element.

const cardEmbed = lithicEmbed.card(sessionToken);
await cardEmbed.mountPan("#pan");

Using callbacks

You can configure callbacks to handle asynchronous notifications from the embeds.

import LithicEmbed, {
    CardDetailsRequestError,
    Environment,
    PinSubmissionError,
    EmbedUpdateState,
} from "lithic-embed";

// Using your api-key generate a session token from your backend
const sessionToken = await fetchSessionToken();
const lithicEmbed = new LithicEmbed(Environment.PRODUCTION);

// Individual callbacks are optional and are not required
const cardEmbed = lithicEmbed.card(sessionToken, {
    onCopy: (cardEmbedType: CardEmbedType, success: boolean) => {
        // Handle the whether the copy was successful or not
    },
    onUpdate: (state: EmbedUpdateState) => {
        if (state === EmbedUpdateState.EmbedRendered) {
            // Handle the embed rendered state
        }

        if (state === EmbedUpdateState.EmbedCardDetailsLoaded) {
            // Handle the embed card details loaded state
        }
    },
});

Styling the mounted iframe

By default, we remove the border of the iframe for better default usability. To apply additional changes to the iframe, you'll need to apply CSS directly to the iframe via a CSS selector.

#pin > iframe {
    height: 30px;
}

#cvv > iframe {
    height: 30px;
}

Automatic style capture and syncing

By default, the lithic-embed SDK will sync the styles applied to the mount target.

const cardEmbed = lithicEmbed.card(sessionToken, {
    syncStyles: true // Default true. Set to false to disable auto syncing of styles.
});

// Any styles applied #pan will be applied to the embed
await cardEmbed.mountPan("#pan");

// Explicit styles take precedence over computed values
await cardEmbed.mountPan("#pan", {
    "color": "white",
    "letter-spacing": "2px"
});

Setting a PIN

Use a PIN-setting embed to let a cardholder set their PIN.

const pinSettingEmbed = lithicEmbed.pinSetting(sessionToken);
await pinSettingEmbed.mount("#pin");

try {
    await pinSettingEmbed.submit();
} catch (error) {
    if (error instanceof PinSubmissionError) {
        // Handle a PIN submission failure or SDK timeout. Locally generated
        // timeout errors do not include a code or request ID.
        console.error(error.code);
        console.error(error.requestId);
    }
}

Events

Lithic's modern embedded card ui generates events to notify you of session generation and card detail reveals. These events give you the ability to correlate sessions with the corresponding card reveals. The link is created using the shared session_id found in both the events.

embed.session_generated

API Reference: Embed Session Generated Event

This event is used to notify you of a session being generated along with the IP address used to generate the session.

embed.viewed

API Reference: Embed Viewed Event

This event is used to notify you when an end-user has revealed the card details with the IP address used to reveal the card details.


Did this page help you?