Skip to content
Create account or Sign in
/
Ask AI
Create accountSign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
APIs & SDKsHelp
Overview
Get started with Connect
Design your integration
Integration fundamentals
Example integrations
Account management
Onboard connected accounts
Configure account Dashboards
Capabilities and information requirements
Work with connected account types
Payment processing
Accept payments
Pay out to accounts
Platform administration
Manage your Connect platform
Tax forms for your Connect platform
Embedded finance
Treasury for platforms
Issuing
    Overview
    How Issuing works
    Global availability
    Product and marketing compliance guidance (US)
    Marketing guidance (Europe/UK)
    Manage fraud
    Get started with Issuing
    Onboarding overview
    Choose a cardholder type
    Choose your card type
    Virtual cards
    Physical cards
    Fund your Issuing balance
    Testing
    Integrate Issuing
    Integration guides
    Sample app
    Manage cards
    Digital wallets
    Replacement cards
    Card programs
    Program management
    Processor-only Issuing
    Customize your card program
    Add funds to your card program
    Consumer Credit Issuing
    Consumer prepaid debit cards
    Stablecoin-backed cards
    Controls
    Spending controls
    Lifecycle controls
    Radar
    3DS
    Alerts for updated phone numbers
    Fraud challenges
    Real-time authentications
    Real-time authorizations
    Issuer-app authentications
    PIN management
    Issuing Elements
    Token management
    Postfunding
    Postfund your integration with Stripe
    Postfund your integration with Dynamic Reserves
    Purchases
    Authorizations
    Transactions
    Disputes
    Merchant categories
    ATM usage
    Enriched merchant data
    Issuing with Connect
    Set up an Issuing and Connect integration
    Update terms of service acceptance
    Connect funding
    Connected accounts, cardholders, and cards
    Inactive connected accounts offboarding
    Embed card management UI
    Issuing with Connect and Accounts V2 APIs
    Set up an Issuing and Connect integration
    Credit
    Overview
    Set up connected accounts
    Manage credit terms
    Report other credit decisions and manage AANs
    Report required regulatory data for credit decisions
    Manage account obligations
    Test credit integration
    Additional information
    Customer support for Issuing and Treasury for platforms
    Issuing watchlist
Capital for platforms
Managed support
United States
English (United States)
  1. Home/
  2. Platforms and marketplaces/
  3. Issuing

Using Issuing Elements

Learn how to display card details in your web application in a PCI-compliant way.

Stripe.js includes a browser-side JavaScript library you can use to display the sensitive data of your Issuing cards on the web in compliance with PCI requirements. The sensitive data renders inside Stripe-hosted iframes and never touches your servers. Stripe.js also collects extra data to protect your users. Learn more about how Stripe collects data for advanced fraud detection.

Ephemeral key authentication

Stripe.js uses ephemeral keys to securely retrieve Card information from the Stripe API without publicly exposing your secret keys. You need to do some of the ephemeral key exchange on the server-side to set this up.

The ephemeral key creation process begins in the browser, by creating a nonce using Stripe.js. A nonce is a single-use token that creates an ephemeral key. This nonce is sent to your server, where you exchange it for an ephemeral key by calling the Stripe API (using your secret key).

Create a server-side ephemeral key, then pass it back to the browser for Stripe.js to use.

Create a secure endpoint
Server-side

The first step to integrating with Issuing Elements is to create a secure, server-side endpoint to generate ephemeral keys for the card you want to show. Your Issuing Elements web integration calls this endpoint. When creating ephemeral keys, specify an API version of 2020-03-02 or later and include the ephemeral key nonce, which you create in your web integration.

Here’s how you might implement an ephemeral key creation endpoint in web applications framework across various languages:

server.js
Node.js
Ruby
PHP
Python
Go
Java
.NET
No results
// This example sets up an endpoint using the Express framework. const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.urlencoded({ extended: true })); // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. const stripe = require('stripe')('sk_test_BQokikJOvBiI2HlWgH4olfQ2'); app.post('/ephemeral-keys', async (request, response) => { const { card_id, nonce } = request.body; /* Important: Authenticate your user here! */ const ephemeralKey = await stripe.ephemeralKeys.create({ nonce: nonce, issuing_card: card_id, }, { apiVersion: '2026-08-26.dahlia', }); response.json({ ephemeralKeySecret: ephemeralKey.secret, }); });

Create a secure endpoint with Connect

To create a secure endpoint as a Connect user, add Stripe-Account in the header.

server.js
Node.js
Ruby
PHP
Python
Go
Java
.NET
No results
const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.urlencoded({ extended: true })); const stripe = require('stripe')('sk_test_51SwlWHCo8vLtpLsixyTaljaqf0iIAgSoH5A2TG21adZ9nas0LWFGEwJhpmAKZ3LaM0nMhR0a7AWzCR3CBxnyyQrK000Y8iN4CQ'); app.post('/ephemeral-keys', async (request, response) => { const { card_id, nonce } = request.body; /* Important: Authenticate your user here! */ const ephemeralKey = await stripe.ephemeralKeys.create({ nonce: nonce, issuing_card: card_id, }, { apiVersion: '2026-01-28.clover', stripeAccount: connectedAccountToken, }); response.json({ ephemeralKeySecret: ephemeralKey.secret, }); });

Common mistake

Your endpoint is responsible for authenticating that the requesting user has permission to see the requested card’s details. Make sure your endpoint only issues ephemeral keys to users of the requested card.

Web API integration
Client-side

First, include Stripe.js on your page. For more information on how to set up Stripe.js, refer to including Stripe.js.

Create a Stripe instance and an ephemeral key nonce for the card you want to retrieve using stripe.createEphemeralKeyNonce. Use the nonce to retrieve the ephemeral key by calling the server-side endpoint that you created:

const stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx'); // Initialize Elements which you'll need later const elements = stripe.elements(); // Use Stripe.js to create a nonce const cardId =
'{{CARD_ID}}'
; const nonceResult = await stripe.createEphemeralKeyNonce({ issuingCard: cardId, }); const nonce = nonceResult.nonce; // Call your ephemeral key creation endpoint to fetch the ephemeral key. // Note that the ephemeral key expires after 15 minutes. const ephemeralKeyResult = await fetch('/ephemeral-keys', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': /* Important: this endpoint must be authenticated. */ }, body: JSON.stringify({ card_id: cardId, nonce: nonce, }) }); const ephemeralKeyResponse = await ephemeralKeyResult.json(); const ephemeralKeySecret = ephemeralKeyResponse.ephemeralKeySecret; // Retrieve card data — must be called before creating Issuing Elements await stripe.retrieveIssuingCard(cardId, { ephemeralKeySecret: ephemeralKeySecret, nonce: nonce, });

Web API integration with Connect

If you use Connect, you must initialize Stripe with beta flags for Issuing Elements.

Feature flag required

If you want to use Issuing Elements with connected accounts, you need to contact Stripe Support to request access. Otherwise, creating ephemeral keys on behalf of connected accounts fails with authorization errors.

// Initialize Stripe with beta flags for Issuing Elements const stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx', { stripeAccount:
'{{CONNECTED_ACCOUNT_ID}}'
, betas: [ 'issuing_add_to_wallet_button_element_1', 'issuing_elements_2', ] }); // Initialize Elements which you'll need later const elements = stripe.elements(); // Use Stripe.js to create a nonce const cardId =
'{{CARD_ID}}'
; const nonceResult = await stripe.createEphemeralKeyNonce({ issuingCard: cardId, }); const nonce = nonceResult.nonce; // Call your ephemeral key creation endpoint to fetch the ephemeral key. // Note that the ephemeral key expires after 15 minutes. const ephemeralKeyResult = await fetch('/ephemeral-keys', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': /* Important: this endpoint must be authenticated. */ }, body: JSON.stringify({ card_id: cardId, nonce: nonce, }) }); const ephemeralKeyResponse = await ephemeralKeyResult.json(); const ephemeralKeySecret = ephemeralKeyResponse.ephemeralKeySecret; // When using the issuing_elements_2 beta with Connect, you must call // retrieveIssuingCard before creating elements. Without this step, element // creation fails with "Issuing card has not been retrieved." The returned // cardResult isn't used directly. Elements need the card registered internally // with Stripe.js to mount. const cardResult = await stripe.retrieveIssuingCard(cardId, { ephemeralKeySecret: ephemeralKeySecret, nonce: nonce, });

Refresh ephemeral key every 15 minutes

Ephemeral keys for Issuing Elements expire after 15 minutes. Call your backend endpoint every 15 minutes during a user session to refresh the ephemeral key and prevent stale authentication.

After regenerating, use the Element’s update({...}) method to send in a new ephemeral key and nonce.

Display an Element
Client-side

Now that you have an ephemeral key and have called stripe.retrieveIssuingCard(), you can display an Issuing Element.

All Elements are created with the following pattern:

const element = elements.create(elementName, options); element.mount("#my-parent-container");

Available Issuing Elements

ElementNameAvailability
Number (PAN)issuingCardNumberDisplayVirtual cards only
CVCissuingCardCvcDisplayVirtual cards only
Expiry dateissuingCardExpiryDisplayAny card
PINissuingCardPinDisplayAny card
Copy buttonissuingCardCopyButtonAny card

Common mistake

In a sandbox, all card data, including the number and CVC, is returned for any card type, regardless of the restrictions above. In live mode, issuingCardNumberDisplay and issuingCardCvcDisplay return data for virtual cards only by default. To display the number and CVC for physical cards in live mode, you must request access to the allow_retrieve_physical_card_details feature by contacting Stripe support.

Display physical card details

By default, PAN and CVC elements only work with virtual cards. To display these details for physical cards, you need to:

  1. Request access: Contact Stripe support to request the allow_retrieve_physical_card_details feature for your account.
  2. Enable the beta flag: Initialize Stripe.js with the issuing_elements_2 beta flag:
const stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx', { betas: ['issuing_elements_2'], });

When both requirements are met, issuingCardNumberDisplay and issuingCardCvcDisplay work for physical cards as they do for virtual cards.

Usage

Each element type has different options and functions. Select which element type you want to learn more about:

This section applies to creating elements that display a card’s details: issuingCardNumberDisplay, issuingCardCvcDisplay, issuingCardExpiryDisplay, or issuingCardPinDisplay.

Options

NameTypeUsageRequired
issuingCardstringThe ID of your issued card (for example, ic_abc123)Yes
noncestringYour ephemeral key nonceYes
ephemeralKeySecretstringThe secret component of your ephemeral keyYes
styleStyle objectKeep in mind that some variants, pseudo-classes, and properties are for input Elements and won’t apply to these Elements. An example of an input-only pseudo-class is ::placeholder.No

Example

const number = elements.create('issuingCardNumberDisplay', { issuingCard: cardId, nonce: nonce, ephemeralKeySecret: ephemeralKeySecret, style: { base: { color: '#fff', fontSize: '16px' }, }, }); number.mount('#card-number');

Security requirements

If you choose to use issuingCardPinDisplay, you must implement measures to ensure that only authorized users can access it. Specifically, you need to apply two-factor authentication (2FA) before granting access to any page that uses issuingCardPinDisplay. If Stripe determines that your security measures are inadequate, we might suspend your access to this Element.

Note

Unlike our mobile SDKs, Issuing Elements doesn’t provide an integration with verifications. You must implement two-factor authentication in order to display card PINs through Issuing Elements.

Additional details

The returned card object has PCI fields (such as the number) fully removed from the result.issuingCard payload.

In addition to .mount() in the previous examples, the Elements also support the following methods:

  • .destroy()
  • .unmount()
  • .update(options)

Issuing Elements and native applications

Issuing Elements doesn’t directly support native application platforms such as iOS, Android, or React Native.

To display sensitive card details with Issuing Elements in your native app, use a web view. Build a web integration on your servers following this guide, and then point a web view’s URL to that integration. To learn about implementing web views for native apps, see these external resources:

  • iOS and iPadOS: WKWebView
  • Android: WebView
  • React Native: react-native-webview
  • Flutter: webview-flutter
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Chat with Stripe developers on Discord.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc
On this page