CapsuleCredit
← All posts

Virtual Card Issuance: 5 Steps to Scale Payments Fast

May 13, 2026

▶ Watch the 60-second version on YouTube

Seamless Virtual Card Issuance Using Stripe and Lithic

Scaling payment solutions with virtual cards is a game changer for fintech developers. It allows for precise control over spending, improved security, and a streamlined user experience. In this post, we'll dive into how to set up virtual card issuance using Stripe Issuing and Lithic, and provide you with practical examples to get you up and running quickly.

Why Use Virtual Cards?

Virtual cards offer unique benefits for both developers and end-users:
  • Enhanced Security: Virtual cards reduce the risk of fraud as they can be generated on-the-fly, limiting exposure of your real card numbers.
  • Spending Controls: Set limits on how much a card can spend, or restrict it to specific merchants.
  • Easy Integration: APIs from Stripe and Lithic make it simple to implement virtual cards into your application.
Now, let’s look at how to leverage these platforms to create a virtual card issuance solution.

Step 1: Set Up Your Environment

Before you can issue virtual cards, make sure you have authenticated your application with the necessary APIs. For Stripe, you need to set up your Stripe account and retrieve your API keys. Similarly, create an account with Lithic and obtain your credentials.

Step 2: Create a Stripe Issuing Card

Using Stripe Issuing, you can create a virtual card in just a few API calls. Here’s a code snippet showing how to create a card in Python:

import stripe

# Initialize Stripe with your secret key
stripe.api_key = "sk_test_your_secret_key"

# Create an Issuing Card
card = stripe.issuing.Card.create(
    user="user_id",
    type="virtual",
    currency="usd",
    cardholder={"name": "Cardholder Name"},
    spending_controls={
        "allowed_categories": ["business_services"],
        "blocked_categories": ["gambling"],
        "spending_limits": [{
            "amount": 10000,  # Limit in cents
            "interval": "monthly"
        }]
    }
)

print("Created virtual card: ", card.id)
This example creates a virtual card with specified spending controls and limits.

Step 3: Integrate with Lithic

Once you’ve created a virtual card with Stripe, you may want to integrate it with Lithic for additional features, like tokenization or enhanced spending controls. Here’s how to generate a card on Lithic:

import requests

# Define your Lithic API endpoint and credentials
lithic_url = "https://api.lithic.com/v1/cards"
headers = {
    "Authorization": "Bearer your_lithic_api_key",
    "Content-Type": "application/json"
}

# Create a virtual card with Lithic
lithic_response = requests.post(
    lithic_url,
    headers=headers,
    json={
        "card_type": "virtual",
        "currency": "USD",
        "merchant_categories": ["grocery", "utilities"],
        "spending_controls": {
            "max_amount": 5000,  # Set maximum spend limit
            "max_frequency": "daily"
        }
    }
)

print("Lithic card creation response: ", lithic_response.json())
Lithic offers a robust API for issuing cards that you can easily integrate with your existing payment workflows.

Step 4: Tokenization with Visa Token Service

Incorporating tokenization improves security and compliance. Integrate with Visa Token Service (VTS) to tokenize your cards. When making a payment, use the tokenized card number instead of the real card number. This can be done like this:

curl -X POST https://api.visa.com/vts/v1/tokens \
-H 'Authorization: Bearer your_vts_api_key' \
-H 'Content-Type: application/json' \
-d '{
  "primaryAccountNumber": "4111111111111111",
  "expirationDate": "12/25",
  "serviceCode": "101"
}'
This will return a token that you can use in place of the original card number, adding a layer of security to your transactions.

Step 5: Monitor and Adjust Spending Controls

Once your virtual cards are live, monitoring spending and adjusting controls is crucial. Use webhook notifications from both Stripe and Lithic to track card usage in real-time. Here’s a gotcha to watch out for: **Webhook Handling** Both Stripe and Lithic send events when transactions occur, including failed transactions or when spending limits are reached. Ensure your application correctly handles these events. For example, if your webhook fails to respond in a timely manner (e.g., 5 seconds), Stripe may retry the webhook, leading to duplicate processing. Make sure to implement idempotency in your webhook handling logic to avoid processing the same event multiple times. Here's a basic example of how to set up your webhook endpoint:

from flask import Flask, request

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def stripe_webhook():
    payload = request.get_data(as_text=True)
    sig_header = request.headers.get('Stripe-Signature')
    
    # Verify the webhook signature here...

    event = None
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, stripe_endpoint_secret
        )
    except ValueError as e:
        # Invalid payload
        return '', 400
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        return '', 400

    # Handle the event
    if event['type'] == 'issuing.card.updated':
        # Process card update
        pass

    return '', 200
By setting up a robust webhook handler, you can keep track of your virtual cards and respond effectively to changes in their status. With these steps, you can implement virtual card issuance that scales seamlessly with your fintech application. Whether you're enhancing user security, controlling spending, or simplifying payment processes, virtual cards offer a flexible solution to meet modern payment needs.

💳 Best card for API and cloud spend — earn rewards on every Stripe, AWS, and OpenAI charge.

Get Brex →