Stripe API wrapper for Node.js providing comprehensive payment processing, subscription management, and financial services integration.
—
Stripe Issuing enables you to create, manage, and control corporate cards. This comprehensive card issuing platform provides capabilities for virtual and physical card creation, real-time authorization controls, transaction monitoring, and dispute management.
Create and manage virtual and physical cards:
interface IssuingCard {
id: string;
object: 'issuing.card';
cardholder: string;
type: 'virtual' | 'physical';
status: 'active' | 'inactive' | 'canceled' | 'lost' | 'stolen';
brand: 'visa' | 'mastercard';
currency: string;
spending_controls: {
allowed_categories?: string[];
blocked_categories?: string[];
spending_limits?: Array<{
amount: number;
categories?: string[];
interval: 'per_authorization' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'all_time';
}>;
};
created: number;
exp_month: number;
exp_year: number;
last4: string;
}
// Create virtual card
const virtualCard = await stripe.issuing.cards.create({
cardholder: 'ich_cardholder_123',
currency: 'usd',
type: 'virtual',
spending_controls: {
spending_limits: [
{
amount: 50000, // $500 limit
interval: 'monthly'
}
],
allowed_categories: ['fuel_and_gas_stations', 'restaurants']
},
metadata: {
employee_id: 'emp_123',
department: 'marketing'
}
});
// Create physical card
const physicalCard = await stripe.issuing.cards.create({
cardholder: 'ich_cardholder_456',
currency: 'usd',
type: 'physical',
shipping: {
address: {
line1: '123 Main St',
city: 'San Francisco',
state: 'CA',
postal_code: '94105',
country: 'US'
},
name: 'John Doe',
service: 'standard'
},
spending_controls: {
spending_limits: [
{
amount: 100000, // $1,000 monthly limit
interval: 'monthly'
},
{
amount: 5000, // $50 per transaction
interval: 'per_authorization'
}
]
}
});
// Create card with category restrictions
const restrictedCard = await stripe.issuing.cards.create({
cardholder: 'ich_cardholder_789',
currency: 'usd',
type: 'virtual',
spending_controls: {
blocked_categories: [
'gambling',
'adult_digital_goods',
'liquor_stores'
],
allowed_categories: [
'gas_stations',
'grocery_stores',
'restaurants',
'office_supplies'
]
}
});
// Retrieve card
const retrieved = await stripe.issuing.cards.retrieve('ic_123', {
expand: ['cardholder']
});
// Update card
const updated = await stripe.issuing.cards.update('ic_123', {
status: 'inactive',
spending_controls: {
spending_limits: [
{
amount: 25000, // Reduced to $250 monthly
interval: 'monthly'
}
]
},
metadata: {
status_reason: 'employee_left'
}
});
// List cards
const cards = await stripe.issuing.cards.list({
cardholder: 'ich_cardholder_123',
status: 'active',
limit: 20
});
// List cards by type
const physicalCards = await stripe.issuing.cards.list({
type: 'physical',
status: 'active'
});Manage individuals authorized to use issued cards:
interface IssuingCardholder {
id: string;
object: 'issuing.cardholder';
type: 'individual' | 'company';
name: string;
email?: string;
phone_number?: string;
status: 'active' | 'inactive' | 'blocked';
billing: {
address: Address;
};
individual?: {
first_name: string;
last_name: string;
dob?: {
day: number;
month: number;
year: number;
};
verification?: {
document?: {
back?: string;
front?: string;
};
};
};
company?: {
tax_id?: string;
};
}
// Create individual cardholder
const individual = await stripe.issuing.cardholders.create({
type: 'individual',
name: 'John Doe',
email: 'john.doe@company.com',
phone_number: '+15555551234',
billing: {
address: {
line1: '123 Main St',
line2: 'Apt 4B',
city: 'San Francisco',
state: 'CA',
postal_code: '94105',
country: 'US'
}
},
individual: {
first_name: 'John',
last_name: 'Doe',
dob: {
day: 15,
month: 6,
year: 1990
}
}
});
// Create company cardholder
const company = await stripe.issuing.cardholders.create({
type: 'company',
name: 'Acme Corp Employee Cards',
email: 'finance@acme.com',
billing: {
address: {
line1: '456 Business Ave',
city: 'New York',
state: 'NY',
postal_code: '10001',
country: 'US'
}
},
company: {
tax_id: '123456789'
}
});
// Create cardholder with identity verification
const verifiedCardholder = await stripe.issuing.cardholders.create({
type: 'individual',
name: 'Jane Smith',
email: 'jane.smith@company.com',
billing: {
address: {
line1: '789 Oak St',
city: 'Austin',
state: 'TX',
postal_code: '73301',
country: 'US'
}
},
individual: {
first_name: 'Jane',
last_name: 'Smith',
verification: {
document: {
front: 'file_identity_front',
back: 'file_identity_back'
}
}
}
});
// Retrieve cardholder
const retrieved = await stripe.issuing.cardholders.retrieve('ich_123');
// Update cardholder
const updated = await stripe.issuing.cardholders.update('ich_123', {
email: 'newemail@company.com',
phone_number: '+15555559999',
status: 'inactive'
});
// List cardholders
const cardholders = await stripe.issuing.cardholders.list({
status: 'active',
limit: 20
});
// List cardholders by type
const individuals = await stripe.issuing.cardholders.list({
type: 'individual',
email: 'john@company.com'
});Monitor and manage card transactions:
interface IssuingTransaction {
id: string;
object: 'issuing.transaction';
card: string;
cardholder?: string;
type: 'capture' | 'refund';
amount: number;
currency: string;
authorization?: string;
merchant_data: {
category: string;
name: string;
network_id: string;
city?: string;
country?: string;
};
purchase_details?: {
flight?: FlightDetails;
fuel?: FuelDetails;
lodging?: LodgingDetails;
receipt?: ReceiptDetails[];
};
created: number;
status: 'pending' | 'posted';
}
// Retrieve transaction
const transaction = await stripe.issuing.transactions.retrieve('ipi_123', {
expand: ['card', 'cardholder']
});
// Update transaction
const updated = await stripe.issuing.transactions.update('ipi_123', {
metadata: {
category: 'travel',
expense_report_id: 'exp_456'
}
});
// List transactions
const transactions = await stripe.issuing.transactions.list({
card: 'ic_123',
limit: 50
});
// List transactions by date range
const recentTransactions = await stripe.issuing.transactions.list({
cardholder: 'ich_123',
created: {
gte: Math.floor(Date.now() / 1000) - 86400 * 30 // Last 30 days
}
});
// List transactions by merchant category
const restaurantTransactions = await stripe.issuing.transactions.list({
card: 'ic_123',
'merchant_data[category]': 'restaurants'
});Manage real-time authorization decisions:
interface IssuingAuthorization {
id: string;
object: 'issuing.authorization';
card: string;
cardholder?: string;
amount: number;
currency: string;
status: 'pending' | 'closed' | 'reversed';
approved: boolean;
authorization_method: 'chip' | 'contactless' | 'keyed_in' | 'swipe' | 'online';
merchant_data: {
category: string;
name: string;
network_id: string;
city?: string;
country?: string;
};
verification_data: {
address_line1_check?: 'match' | 'mismatch' | 'not_provided';
address_postal_code_check?: 'match' | 'mismatch' | 'not_provided';
cvc_check?: 'match' | 'mismatch' | 'not_provided';
};
}
// Retrieve authorization
const authorization = await stripe.issuing.authorizations.retrieve('iauth_123', {
expand: ['card', 'cardholder']
});
// Approve authorization
const approved = await stripe.issuing.authorizations.approve('iauth_123', {
amount: 5000 // Approve for $50
});
// Decline authorization
const declined = await stripe.issuing.authorizations.decline('iauth_123', {
reason: 'insufficient_funds'
});
// Update authorization
const updated = await stripe.issuing.authorizations.update('iauth_123', {
metadata: {
approval_reason: 'manual_review_approved',
reviewer: 'admin_123'
}
});
// List authorizations
const authorizations = await stripe.issuing.authorizations.list({
card: 'ic_123',
status: 'pending',
limit: 20
});
// List declined authorizations
const declined = await stripe.issuing.authorizations.list({
cardholder: 'ich_123',
approved: false
});Handle disputes for issued card transactions:
interface IssuingDispute {
id: string;
object: 'issuing.dispute';
transaction: string;
status: 'unsubmitted' | 'submitted' | 'won' | 'lost' | 'expired';
reason: 'fraudulent' | 'subscription_canceled' | 'product_unacceptable' | 'product_not_received' | 'unrecognized' | 'duplicate' | 'credit_not_processed' | 'general' | 'incorrect_amount' | 'canceled_recurring' | 'paid_by_other_means' | 'emv_liability_shift';
amount: number;
currency: string;
evidence: {
fraudulent?: {
dispute_explanation?: string;
uncategorized_file?: string;
};
other?: {
dispute_explanation?: string;
uncategorized_file?: string;
};
};
}
// Create dispute
const dispute = await stripe.issuing.disputes.create({
transaction: 'ipi_transaction_123',
reason: 'fraudulent',
evidence: {
fraudulent: {
dispute_explanation: 'This transaction was not authorized by the cardholder.',
uncategorized_file: 'file_evidence_123'
}
}
});
// Create product dispute
const productDispute = await stripe.issuing.disputes.create({
transaction: 'ipi_transaction_456',
reason: 'product_not_received',
evidence: {
other: {
dispute_explanation: 'Product was never delivered despite payment.',
uncategorized_file: 'file_shipping_evidence'
}
}
});
// Retrieve dispute
const retrieved = await stripe.issuing.disputes.retrieve('idp_123');
// Update dispute evidence
const updated = await stripe.issuing.disputes.update('idp_123', {
evidence: {
fraudulent: {
dispute_explanation: 'Updated explanation with additional details.',
uncategorized_file: 'file_additional_evidence'
}
}
});
// List disputes
const disputes = await stripe.issuing.disputes.list({
status: 'unsubmitted',
limit: 20
});
// List disputes by transaction
const transactionDisputes = await stripe.issuing.disputes.list({
transaction: 'ipi_123'
});
// Submit dispute
const submitted = await stripe.issuing.disputes.submit('idp_123');Customize physical card appearance:
interface IssuingPersonalizationDesign {
id: string;
object: 'issuing.personalization_design';
physical_bundle: string;
name: string;
status: 'active' | 'inactive' | 'rejected' | 'requires_review';
card_logo?: string;
carrier_text?: {
footer_body?: string;
footer_title?: string;
header_body?: string;
header_title?: string;
};
lookup_key?: string;
}
// Create personalization design
const design = await stripe.issuing.personalizationDesigns.create({
physical_bundle: 'pb_standard_visa',
name: 'Company Branded Design',
card_logo: 'file_company_logo',
carrier_text: {
header_title: 'Welcome to Acme Corp',
header_body: 'Your corporate card',
footer_title: 'Questions?',
footer_body: 'Call 1-800-ACME-123'
},
lookup_key: 'acme_standard_design'
});
// Retrieve personalization design
const retrieved = await stripe.issuing.personalizationDesigns.retrieve('pd_123');
// Update personalization design
const updated = await stripe.issuing.personalizationDesigns.update('pd_123', {
name: 'Updated Company Design',
carrier_text: {
header_title: 'Acme Corporation',
footer_body: 'Support: support@acme.com'
}
});
// List personalization designs
const designs = await stripe.issuing.personalizationDesigns.list({
status: 'active',
limit: 10
});
// Activate design
const activated = await stripe.issuing.personalizationDesigns.activate('pd_123');
// Deactivate design
const deactivated = await stripe.issuing.personalizationDesigns.deactivate('pd_123');
// Reject design
const rejected = await stripe.issuing.personalizationDesigns.reject('pd_123', {
rejection_reasons: {
card_logo: ['geographic_location']
}
});Available physical card templates:
interface IssuingPhysicalBundle {
id: string;
object: 'issuing.physical_bundle';
name: string;
type: 'custom' | 'standard';
status: 'active' | 'inactive' | 'review';
features: {
card_logo: 'optional' | 'required' | 'unsupported';
carrier_text: 'optional' | 'required' | 'unsupported';
second_line: 'optional' | 'required' | 'unsupported';
};
}
// Retrieve physical bundle
const bundle = await stripe.issuing.physicalBundles.retrieve('pb_123');
// List available physical bundles
const bundles = await stripe.issuing.physicalBundles.list({
status: 'active'
});
// Filter bundles by features
const logoSupportedBundles = bundles.data.filter(
bundle => bundle.features.card_logo !== 'unsupported'
);Manage digital wallet tokens:
interface IssuingToken {
id: string;
object: 'issuing.token';
card: string;
status: 'active' | 'inactive' | 'suspended';
wallet_provider: 'apple_pay' | 'google_pay' | 'samsung_pay';
device_fingerprint?: string;
network_data?: {
device?: {
device_id?: string;
ip_address?: string;
location?: string;
};
wallet?: {
account_id?: string;
};
};
}
// Retrieve token
const token = await stripe.issuing.tokens.retrieve('it_123');
// Update token
const updated = await stripe.issuing.tokens.update('it_123', {
status: 'suspended'
});
// List tokens
const tokens = await stripe.issuing.tokens.list({
card: 'ic_123',
status: 'active'
});
// List tokens by wallet provider
const applePayTokens = await stripe.issuing.tokens.list({
wallet_provider: 'apple_pay'
});Simulate issuing scenarios in test mode:
// Test card delivery
const delivered = await stripe.testHelpers.issuing.deliverCard('ic_test_123');
// Test card failure
const failed = await stripe.testHelpers.issuing.failCard('ic_test_123');
// Test card return
const returned = await stripe.testHelpers.issuing.returnCard('ic_test_123');
// Test card shipping
const shipped = await stripe.testHelpers.issuing.shipCard('ic_test_123');
// Test authorization capture
const captured = await stripe.testHelpers.issuing.capture('iauth_test_123', {
capture_amount: 1000
});
// Test authorization expiry
const expired = await stripe.testHelpers.issuing.expire('iauth_test_123');
// Test authorization increment
const incremented = await stripe.testHelpers.issuing.increment('iauth_test_123', {
increment_amount: 500,
is_amount_controllable: true
});
// Test authorization reversal
const reversed = await stripe.testHelpers.issuing.reverse('iauth_test_123', {
reverse_amount: 2000
});
// Test transaction creation (force capture)
const forceCapture = await stripe.testHelpers.issuing.createForceCapture({
card: 'ic_test_123',
amount: 3000,
currency: 'usd',
merchant_data: {
category: 'restaurants',
name: 'Test Restaurant',
network_id: 'test_merchant_123'
}
});
// Test unlinked refund
const unlinkedRefund = await stripe.testHelpers.issuing.createUnlinkedRefund({
card: 'ic_test_123',
amount: 1500,
currency: 'usd'
});
// Test transaction refund
const refunded = await stripe.testHelpers.issuing.refund('ipi_test_123', {
refund_amount: 1000
});// Webhook handler for authorization requests
app.post('/issuing-webhook', async (req, res) => {
const event = req.body;
if (event.type === 'issuing_authorization.request') {
const authorization = event.data.object;
// Custom authorization logic
const shouldApprove = await evaluateAuthorization(authorization);
if (shouldApprove) {
await stripe.issuing.authorizations.approve(authorization.id);
} else {
await stripe.issuing.authorizations.decline(authorization.id, {
reason: 'spending_controls'
});
}
}
res.status(200).send('OK');
});
async function evaluateAuthorization(auth) {
// Check spending limits
const monthlySpend = await getMonthlySpending(auth.card);
if (monthlySpend + auth.amount > MONTHLY_LIMIT) {
return false;
}
// Check merchant category
const blockedCategories = ['gambling', 'adult_digital_goods'];
if (blockedCategories.includes(auth.merchant_data.category)) {
return false;
}
// Check business hours for certain categories
if (auth.merchant_data.category === 'restaurants') {
const businessHours = isBusinessHours();
return businessHours;
}
return true;
}// Create cards for expense categories
const travelCard = await stripe.issuing.cards.create({
cardholder: 'ich_employee_123',
currency: 'usd',
type: 'virtual',
spending_controls: {
allowed_categories: [
'airlines',
'car_rental',
'lodging',
'restaurants'
],
spending_limits: [{
amount: 200000, // $2,000 monthly travel budget
interval: 'monthly'
}]
},
metadata: {
expense_category: 'travel',
employee_id: 'emp_123'
}
});
// Monitor transactions for expense reporting
const transactions = await stripe.issuing.transactions.list({
card: travelCard.id
});
for (const transaction of transactions.data) {
await createExpenseEntry({
employee_id: transaction.metadata?.employee_id,
category: transaction.merchant_data.category,
amount: transaction.amount,
merchant: transaction.merchant_data.name,
date: new Date(transaction.created * 1000)
});
}interface Address {
/** City/District/Suburb/Town/Village */
city: string | null;
/** 2-letter country code */
country: string | null;
/** Address line 1 (Street address/PO Box/Company name) */
line1: string | null;
/** Address line 2 (Apartment/Suite/Unit/Building) */
line2: string | null;
/** ZIP or postal code */
postal_code: string | null;
/** State/County/Province/Region */
state: string | null;
}
interface FlightDetails {
/** The time that the flight departed */
departure_at: number | null;
/** The name of the passenger */
passenger_name: string | null;
/** Whether the ticket is refundable */
refundable: boolean | null;
/** The legs of the trip */
segments: Array<{
/** The three-letter IATA airport code of the flight's destination */
arrival_airport_code: string | null;
/** The airline carrier code */
carrier: string | null;
/** The three-letter IATA airport code that the flight departed from */
departure_airport_code: string | null;
/** The flight number */
flight_number: string | null;
/** The flight's service class */
service_class: string | null;
/** Whether a stopover is allowed on this flight */
stopover_allowed: boolean | null;
}> | null;
/** The travel agency that issued the ticket */
travel_agency: string | null;
}
interface FuelDetails {
/** Conexxus Payment System Product Code identifying the primary fuel product purchased */
industry_product_code: string | null;
/** The quantity of units of fuel that was dispensed, represented as a decimal string with at most 12 decimal places */
quantity_decimal: string | null;
/** The type of fuel that was purchased. One of 'diesel', 'unleaded_plus', 'unleaded_regular', 'unleaded_super', or 'other' */
type: string;
/** The units for quantity_decimal. One of 'charging_minute', 'imperial_gallon', 'kilogram', 'kilowatt_hour', 'liter', 'pound', 'us_gallon', or 'other' */
unit: string;
/** The cost in cents per each unit of fuel, represented as a decimal string with at most 12 decimal places */
unit_cost_decimal: string;
}
interface LodgingDetails {
/** The time of checking into the lodging */
check_in_at: number | null;
/** The number of nights stayed at the lodging */
nights: number | null;
}
interface ReceiptDetails {
/** The description of the item. The maximum length of this field is 26 characters */
description: string | null;
/** The quantity of the item */
quantity: number | null;
/** The total for this line item in cents */
total: number | null;
/** The unit cost of the item in cents */
unit_cost: number | null;
}Stripe Issuing provides a complete card issuing platform with sophisticated controls, real-time monitoring, and comprehensive dispute management capabilities for modern corporate card programs.
Install with Tessl CLI
npx tessl i tessl/npm-stripe