> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.mercoa.com/virtual-card-agent/process-card-payments/stripe-issuing/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.mercoa.com/_mcp/server.
# Stripe Issuing
## Overview
Stripe Issuing lets you create virtual cards that can be used with the Mercoa Virtual Card Agent to process invoice payments securely.
## Integration Setup
### Enable Stripe Issuing in Stripe Account
To start using Stripe Issuing, ensure your Stripe account has it enabled:
1. Log in to your [Stripe Dashboard](https://dashboard.stripe.com).
2. Click **Issuing** from the left-hand menu.
3. Complete the Issuing application process.
4. Locate and save your `publishable_key` and `secret_key`.
### Create Virtual Card
Create virtual cards for specific invoices:
```javascript
const virtualCard = await stripe.issuing.cards.create({
cardholder: cardholder.id,
currency: 'usd',
status: 'active',
type: 'virtual',
spending_controls: {
spending_limits: [
{
interval: 'all_time',
amount: invoice.amount, // amount must be an integer in the currency’s smallest unit* (cents for USD)
}
],
},
metadata: {
invoice_id: invoice.id,
vendor_id: invoice.vendor_id,
},
});
```
> **Note**
>
> This is just an example, please refer to the [Stripe Issuing documentation](https://stripe.com/docs/issuing) for more information.
## API Integration
The Stripe Issuing integration with the Virtual Card Agent provides a secure, automated workflow for processing virtual card payments. This integration uses ephemeral keys and iFrame technology to ensure sensitive card data is handled securely.
### How It Works
The integration follows a secure workflow where your Stripe virtual card is used to process payments through the Virtual Card Agent:
```mermaid
graph LR
A[Stripe Card Details] --> B[Mercoa API]
B --> C[Agent + iFrame]
C --> D[Your Backend]
D --> E[Ephemeral Key]
E --> C
C --> F[Payment Gateway]
```
**Process Flow:**
1. Create a Stripe virtual card with spending controls matching the invoice amount
2. Call the Mercoa API with your card ID and ephemeral key endpoint configuration
3. The agent uses your backend to generate a temporary ephemeral key
4. Secure card data is retrieved through Stripe's iFrame technology
5. The agent completes the payment through the vendor's payment gateway
6. Receipt and confirmation details are captured for reconciliation
### API Request Structure
When using Stripe Issuing with the Virtual Card Agent, your API request should include:
```json
{
"type": "html",
"html": "
Invoice Details
Pay Invoice",
"cardDetails": {
"type": "stripeIssuing",
"firstName": "John",
"lastName": "Doe",
"postalCode": "12345",
"country": "US",
"stripeCardId": "ic_1234567890abcdef",
"stripePublishableKey": "pk_test_1234567890abcdef",
"ephemeralKeyEndpoint": {
"url": "https://api.example.com/ephemeral-keys",
"method": "POST",
"headers": {
"Authorization": "Bearer YOUR_AUTH_SCHEME",
"Content-Type": "application/json"
},
"postBody": "{\"card_id\": \"{{cardId}}\", \"nonce\": \"{{nonce}}\", \"account_id\": \"{{accountId}}\"}"
}
}
}
```
### Field Descriptions
#### Card Details Object
| Field | Type | Required | Description |
| ---------------------- | ------ | -------- | -------------------------------------------------------------------- |
| `type` | string | Yes | Must be `"stripeIssuing"` |
| `firstName` | string | Yes | Cardholder's first name |
| `lastName` | string | Yes | Cardholder's last name |
| `postalCode` | string | Yes | Billing address postal code |
| `country` | string | Yes | Billing address country (ISO code) |
| `stripeAccountId` | string | No | Stripe account ID of connected account (required for Stripe Connect) |
| `stripeCardId` | string | Yes | Stripe Issuing card ID (starts with `ic_`) |
| `stripePublishableKey` | string | Yes | Your Stripe publishable key |
| `ephemeralKeyEndpoint` | object | Yes | Configuration for ephemeral key generation |
#### Ephemeral Key Endpoint
| Field | Type | Required | Description |
| ---------- | ------ | -------- | ------------------------------------------------------ |
| `url` | string | Yes | Your backend endpoint for generating ephemeral keys |
| `method` | string | No | HTTP method (defaults to `POST`) |
| `headers` | object | Yes | HTTP headers for the request (template with variables) |
| `postBody` | string | Yes | Request body (template with variables) |
#### Supported Variables
The `postBody` and `headers` template supports these variables that will be replaced with actual values:
* `{{cardId}}` - The Stripe card ID
* `{{nonce}}` - A unique nonce for this request
* `{{accountId}}` - Your Stripe account ID (if applicable)
### Backend Implementation
Your backend needs to implement an endpoint that generates ephemeral keys. Here's an example:
```javascript
app.post('/ephemeral-keys', async (req, res) => {
const { card_id, nonce, account_id } = req.body;
try {
const ephemeralKey = await stripe.ephemeralKeys.create(
{
issuing_card: card_id,
nonce: nonce,
},
{
apiVersion: '2023-10-16', // Use latest API version
}
);
res.json({
ephemeralKeySecret: ephemeralKey.secret
});
} catch (error) {
res.status(400).json({
error: 'Failed to create ephemeral key'
});
}
});
```
#### Ephemeral Key Response Structure
Your ephemeral key endpoint must return the ephemeral key secret in one of these formats:
**Option 1: Object with `ephemeralKeySecret` property**
```json
{
"ephemeralKeySecret": "ek_live_1234567890abcdef..."
}
```
**Option 2: Object with `secret` property**
```json
{
"secret": "ek_live_1234567890abcdef..."
}
```
**Option 3: Plain string (the ephemeral key secret directly)**
```
"ek_live_1234567890abcdef..."
```
> **Note**
>
> The ephemeral key secret must be a valid Stripe ephemeral key that was created for the specific card and nonce provided in the request.
### Security Considerations
* **Use ephemeral keys** that expire quickly (typically within 1 hour) and are scoped to a single operation.
* **Avoid storing card numbers**. Your backend must not store or process full card data.
* **Ensure PCI compliance** by using Stripe's iframe-based tokenization and minimal card data handling.
* **Enable logging** for all virtual card operations to maintain an audit trail for compliance and traceability.
## Best Practices
### 🔐 Security
* Use one-time virtual cards with exact amounts.
* Set strict spending limits per card.
* Avoid storing card numbers directly.
* Monitor card usage in the [Stripe Dashboard](https://dashboard.stripe.com).
### 📊 Reconciliation
* Store transaction IDs from Stripe with invoice metadata.
* Use metadata to associate cards with invoices.
* Set up webhooks to track card lifecycle and usage.