0
# Issuing
1
2
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.
3
4
## Card Management
5
6
### Issuing.Cards
7
8
Create and manage virtual and physical cards:
9
10
```typescript { .api }
11
interface IssuingCard {
12
id: string;
13
object: 'issuing.card';
14
cardholder: string;
15
type: 'virtual' | 'physical';
16
status: 'active' | 'inactive' | 'canceled' | 'lost' | 'stolen';
17
brand: 'visa' | 'mastercard';
18
currency: string;
19
spending_controls: {
20
allowed_categories?: string[];
21
blocked_categories?: string[];
22
spending_limits?: Array<{
23
amount: number;
24
categories?: string[];
25
interval: 'per_authorization' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'all_time';
26
}>;
27
};
28
created: number;
29
exp_month: number;
30
exp_year: number;
31
last4: string;
32
}
33
34
// Create virtual card
35
const virtualCard = await stripe.issuing.cards.create({
36
cardholder: 'ich_cardholder_123',
37
currency: 'usd',
38
type: 'virtual',
39
spending_controls: {
40
spending_limits: [
41
{
42
amount: 50000, // $500 limit
43
interval: 'monthly'
44
}
45
],
46
allowed_categories: ['fuel_and_gas_stations', 'restaurants']
47
},
48
metadata: {
49
employee_id: 'emp_123',
50
department: 'marketing'
51
}
52
});
53
54
// Create physical card
55
const physicalCard = await stripe.issuing.cards.create({
56
cardholder: 'ich_cardholder_456',
57
currency: 'usd',
58
type: 'physical',
59
shipping: {
60
address: {
61
line1: '123 Main St',
62
city: 'San Francisco',
63
state: 'CA',
64
postal_code: '94105',
65
country: 'US'
66
},
67
name: 'John Doe',
68
service: 'standard'
69
},
70
spending_controls: {
71
spending_limits: [
72
{
73
amount: 100000, // $1,000 monthly limit
74
interval: 'monthly'
75
},
76
{
77
amount: 5000, // $50 per transaction
78
interval: 'per_authorization'
79
}
80
]
81
}
82
});
83
84
// Create card with category restrictions
85
const restrictedCard = await stripe.issuing.cards.create({
86
cardholder: 'ich_cardholder_789',
87
currency: 'usd',
88
type: 'virtual',
89
spending_controls: {
90
blocked_categories: [
91
'gambling',
92
'adult_digital_goods',
93
'liquor_stores'
94
],
95
allowed_categories: [
96
'gas_stations',
97
'grocery_stores',
98
'restaurants',
99
'office_supplies'
100
]
101
}
102
});
103
104
// Retrieve card
105
const retrieved = await stripe.issuing.cards.retrieve('ic_123', {
106
expand: ['cardholder']
107
});
108
109
// Update card
110
const updated = await stripe.issuing.cards.update('ic_123', {
111
status: 'inactive',
112
spending_controls: {
113
spending_limits: [
114
{
115
amount: 25000, // Reduced to $250 monthly
116
interval: 'monthly'
117
}
118
]
119
},
120
metadata: {
121
status_reason: 'employee_left'
122
}
123
});
124
125
// List cards
126
const cards = await stripe.issuing.cards.list({
127
cardholder: 'ich_cardholder_123',
128
status: 'active',
129
limit: 20
130
});
131
132
// List cards by type
133
const physicalCards = await stripe.issuing.cards.list({
134
type: 'physical',
135
status: 'active'
136
});
137
```
138
139
### Issuing.Cardholders
140
141
Manage individuals authorized to use issued cards:
142
143
```typescript { .api }
144
interface IssuingCardholder {
145
id: string;
146
object: 'issuing.cardholder';
147
type: 'individual' | 'company';
148
name: string;
149
email?: string;
150
phone_number?: string;
151
status: 'active' | 'inactive' | 'blocked';
152
billing: {
153
address: Address;
154
};
155
individual?: {
156
first_name: string;
157
last_name: string;
158
dob?: {
159
day: number;
160
month: number;
161
year: number;
162
};
163
verification?: {
164
document?: {
165
back?: string;
166
front?: string;
167
};
168
};
169
};
170
company?: {
171
tax_id?: string;
172
};
173
}
174
175
// Create individual cardholder
176
const individual = await stripe.issuing.cardholders.create({
177
type: 'individual',
178
name: 'John Doe',
179
email: 'john.doe@company.com',
180
phone_number: '+15555551234',
181
billing: {
182
address: {
183
line1: '123 Main St',
184
line2: 'Apt 4B',
185
city: 'San Francisco',
186
state: 'CA',
187
postal_code: '94105',
188
country: 'US'
189
}
190
},
191
individual: {
192
first_name: 'John',
193
last_name: 'Doe',
194
dob: {
195
day: 15,
196
month: 6,
197
year: 1990
198
}
199
}
200
});
201
202
// Create company cardholder
203
const company = await stripe.issuing.cardholders.create({
204
type: 'company',
205
name: 'Acme Corp Employee Cards',
206
email: 'finance@acme.com',
207
billing: {
208
address: {
209
line1: '456 Business Ave',
210
city: 'New York',
211
state: 'NY',
212
postal_code: '10001',
213
country: 'US'
214
}
215
},
216
company: {
217
tax_id: '123456789'
218
}
219
});
220
221
// Create cardholder with identity verification
222
const verifiedCardholder = await stripe.issuing.cardholders.create({
223
type: 'individual',
224
name: 'Jane Smith',
225
email: 'jane.smith@company.com',
226
billing: {
227
address: {
228
line1: '789 Oak St',
229
city: 'Austin',
230
state: 'TX',
231
postal_code: '73301',
232
country: 'US'
233
}
234
},
235
individual: {
236
first_name: 'Jane',
237
last_name: 'Smith',
238
verification: {
239
document: {
240
front: 'file_identity_front',
241
back: 'file_identity_back'
242
}
243
}
244
}
245
});
246
247
// Retrieve cardholder
248
const retrieved = await stripe.issuing.cardholders.retrieve('ich_123');
249
250
// Update cardholder
251
const updated = await stripe.issuing.cardholders.update('ich_123', {
252
email: 'newemail@company.com',
253
phone_number: '+15555559999',
254
status: 'inactive'
255
});
256
257
// List cardholders
258
const cardholders = await stripe.issuing.cardholders.list({
259
status: 'active',
260
limit: 20
261
});
262
263
// List cardholders by type
264
const individuals = await stripe.issuing.cardholders.list({
265
type: 'individual',
266
email: 'john@company.com'
267
});
268
```
269
270
## Transaction Management
271
272
### Issuing.Transactions
273
274
Monitor and manage card transactions:
275
276
```typescript { .api }
277
interface IssuingTransaction {
278
id: string;
279
object: 'issuing.transaction';
280
card: string;
281
cardholder?: string;
282
type: 'capture' | 'refund';
283
amount: number;
284
currency: string;
285
authorization?: string;
286
merchant_data: {
287
category: string;
288
name: string;
289
network_id: string;
290
city?: string;
291
country?: string;
292
};
293
purchase_details?: {
294
flight?: FlightDetails;
295
fuel?: FuelDetails;
296
lodging?: LodgingDetails;
297
receipt?: ReceiptDetails[];
298
};
299
created: number;
300
status: 'pending' | 'posted';
301
}
302
303
// Retrieve transaction
304
const transaction = await stripe.issuing.transactions.retrieve('ipi_123', {
305
expand: ['card', 'cardholder']
306
});
307
308
// Update transaction
309
const updated = await stripe.issuing.transactions.update('ipi_123', {
310
metadata: {
311
category: 'travel',
312
expense_report_id: 'exp_456'
313
}
314
});
315
316
// List transactions
317
const transactions = await stripe.issuing.transactions.list({
318
card: 'ic_123',
319
limit: 50
320
});
321
322
// List transactions by date range
323
const recentTransactions = await stripe.issuing.transactions.list({
324
cardholder: 'ich_123',
325
created: {
326
gte: Math.floor(Date.now() / 1000) - 86400 * 30 // Last 30 days
327
}
328
});
329
330
// List transactions by merchant category
331
const restaurantTransactions = await stripe.issuing.transactions.list({
332
card: 'ic_123',
333
'merchant_data[category]': 'restaurants'
334
});
335
```
336
337
### Issuing.Authorizations
338
339
Manage real-time authorization decisions:
340
341
```typescript { .api }
342
interface IssuingAuthorization {
343
id: string;
344
object: 'issuing.authorization';
345
card: string;
346
cardholder?: string;
347
amount: number;
348
currency: string;
349
status: 'pending' | 'closed' | 'reversed';
350
approved: boolean;
351
authorization_method: 'chip' | 'contactless' | 'keyed_in' | 'swipe' | 'online';
352
merchant_data: {
353
category: string;
354
name: string;
355
network_id: string;
356
city?: string;
357
country?: string;
358
};
359
verification_data: {
360
address_line1_check?: 'match' | 'mismatch' | 'not_provided';
361
address_postal_code_check?: 'match' | 'mismatch' | 'not_provided';
362
cvc_check?: 'match' | 'mismatch' | 'not_provided';
363
};
364
}
365
366
// Retrieve authorization
367
const authorization = await stripe.issuing.authorizations.retrieve('iauth_123', {
368
expand: ['card', 'cardholder']
369
});
370
371
// Approve authorization
372
const approved = await stripe.issuing.authorizations.approve('iauth_123', {
373
amount: 5000 // Approve for $50
374
});
375
376
// Decline authorization
377
const declined = await stripe.issuing.authorizations.decline('iauth_123', {
378
reason: 'insufficient_funds'
379
});
380
381
// Update authorization
382
const updated = await stripe.issuing.authorizations.update('iauth_123', {
383
metadata: {
384
approval_reason: 'manual_review_approved',
385
reviewer: 'admin_123'
386
}
387
});
388
389
// List authorizations
390
const authorizations = await stripe.issuing.authorizations.list({
391
card: 'ic_123',
392
status: 'pending',
393
limit: 20
394
});
395
396
// List declined authorizations
397
const declined = await stripe.issuing.authorizations.list({
398
cardholder: 'ich_123',
399
approved: false
400
});
401
```
402
403
## Dispute Management
404
405
### Issuing.Disputes
406
407
Handle disputes for issued card transactions:
408
409
```typescript { .api }
410
interface IssuingDispute {
411
id: string;
412
object: 'issuing.dispute';
413
transaction: string;
414
status: 'unsubmitted' | 'submitted' | 'won' | 'lost' | 'expired';
415
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';
416
amount: number;
417
currency: string;
418
evidence: {
419
fraudulent?: {
420
dispute_explanation?: string;
421
uncategorized_file?: string;
422
};
423
other?: {
424
dispute_explanation?: string;
425
uncategorized_file?: string;
426
};
427
};
428
}
429
430
// Create dispute
431
const dispute = await stripe.issuing.disputes.create({
432
transaction: 'ipi_transaction_123',
433
reason: 'fraudulent',
434
evidence: {
435
fraudulent: {
436
dispute_explanation: 'This transaction was not authorized by the cardholder.',
437
uncategorized_file: 'file_evidence_123'
438
}
439
}
440
});
441
442
// Create product dispute
443
const productDispute = await stripe.issuing.disputes.create({
444
transaction: 'ipi_transaction_456',
445
reason: 'product_not_received',
446
evidence: {
447
other: {
448
dispute_explanation: 'Product was never delivered despite payment.',
449
uncategorized_file: 'file_shipping_evidence'
450
}
451
}
452
});
453
454
// Retrieve dispute
455
const retrieved = await stripe.issuing.disputes.retrieve('idp_123');
456
457
// Update dispute evidence
458
const updated = await stripe.issuing.disputes.update('idp_123', {
459
evidence: {
460
fraudulent: {
461
dispute_explanation: 'Updated explanation with additional details.',
462
uncategorized_file: 'file_additional_evidence'
463
}
464
}
465
});
466
467
// List disputes
468
const disputes = await stripe.issuing.disputes.list({
469
status: 'unsubmitted',
470
limit: 20
471
});
472
473
// List disputes by transaction
474
const transactionDisputes = await stripe.issuing.disputes.list({
475
transaction: 'ipi_123'
476
});
477
478
// Submit dispute
479
const submitted = await stripe.issuing.disputes.submit('idp_123');
480
```
481
482
## Physical Card Design
483
484
### Issuing.PersonalizationDesigns
485
486
Customize physical card appearance:
487
488
```typescript { .api }
489
interface IssuingPersonalizationDesign {
490
id: string;
491
object: 'issuing.personalization_design';
492
physical_bundle: string;
493
name: string;
494
status: 'active' | 'inactive' | 'rejected' | 'requires_review';
495
card_logo?: string;
496
carrier_text?: {
497
footer_body?: string;
498
footer_title?: string;
499
header_body?: string;
500
header_title?: string;
501
};
502
lookup_key?: string;
503
}
504
505
// Create personalization design
506
const design = await stripe.issuing.personalizationDesigns.create({
507
physical_bundle: 'pb_standard_visa',
508
name: 'Company Branded Design',
509
card_logo: 'file_company_logo',
510
carrier_text: {
511
header_title: 'Welcome to Acme Corp',
512
header_body: 'Your corporate card',
513
footer_title: 'Questions?',
514
footer_body: 'Call 1-800-ACME-123'
515
},
516
lookup_key: 'acme_standard_design'
517
});
518
519
// Retrieve personalization design
520
const retrieved = await stripe.issuing.personalizationDesigns.retrieve('pd_123');
521
522
// Update personalization design
523
const updated = await stripe.issuing.personalizationDesigns.update('pd_123', {
524
name: 'Updated Company Design',
525
carrier_text: {
526
header_title: 'Acme Corporation',
527
footer_body: 'Support: support@acme.com'
528
}
529
});
530
531
// List personalization designs
532
const designs = await stripe.issuing.personalizationDesigns.list({
533
status: 'active',
534
limit: 10
535
});
536
537
// Activate design
538
const activated = await stripe.issuing.personalizationDesigns.activate('pd_123');
539
540
// Deactivate design
541
const deactivated = await stripe.issuing.personalizationDesigns.deactivate('pd_123');
542
543
// Reject design
544
const rejected = await stripe.issuing.personalizationDesigns.reject('pd_123', {
545
rejection_reasons: {
546
card_logo: ['geographic_location']
547
}
548
});
549
```
550
551
### Issuing.PhysicalBundles
552
553
Available physical card templates:
554
555
```typescript { .api }
556
interface IssuingPhysicalBundle {
557
id: string;
558
object: 'issuing.physical_bundle';
559
name: string;
560
type: 'custom' | 'standard';
561
status: 'active' | 'inactive' | 'review';
562
features: {
563
card_logo: 'optional' | 'required' | 'unsupported';
564
carrier_text: 'optional' | 'required' | 'unsupported';
565
second_line: 'optional' | 'required' | 'unsupported';
566
};
567
}
568
569
// Retrieve physical bundle
570
const bundle = await stripe.issuing.physicalBundles.retrieve('pb_123');
571
572
// List available physical bundles
573
const bundles = await stripe.issuing.physicalBundles.list({
574
status: 'active'
575
});
576
577
// Filter bundles by features
578
const logoSupportedBundles = bundles.data.filter(
579
bundle => bundle.features.card_logo !== 'unsupported'
580
);
581
```
582
583
## Token Management
584
585
### Issuing.Tokens
586
587
Manage digital wallet tokens:
588
589
```typescript { .api }
590
interface IssuingToken {
591
id: string;
592
object: 'issuing.token';
593
card: string;
594
status: 'active' | 'inactive' | 'suspended';
595
wallet_provider: 'apple_pay' | 'google_pay' | 'samsung_pay';
596
device_fingerprint?: string;
597
network_data?: {
598
device?: {
599
device_id?: string;
600
ip_address?: string;
601
location?: string;
602
};
603
wallet?: {
604
account_id?: string;
605
};
606
};
607
}
608
609
// Retrieve token
610
const token = await stripe.issuing.tokens.retrieve('it_123');
611
612
// Update token
613
const updated = await stripe.issuing.tokens.update('it_123', {
614
status: 'suspended'
615
});
616
617
// List tokens
618
const tokens = await stripe.issuing.tokens.list({
619
card: 'ic_123',
620
status: 'active'
621
});
622
623
// List tokens by wallet provider
624
const applePayTokens = await stripe.issuing.tokens.list({
625
wallet_provider: 'apple_pay'
626
});
627
```
628
629
## Test Helpers
630
631
### TestHelpers.Issuing
632
633
Simulate issuing scenarios in test mode:
634
635
```typescript { .api }
636
// Test card delivery
637
const delivered = await stripe.testHelpers.issuing.deliverCard('ic_test_123');
638
639
// Test card failure
640
const failed = await stripe.testHelpers.issuing.failCard('ic_test_123');
641
642
// Test card return
643
const returned = await stripe.testHelpers.issuing.returnCard('ic_test_123');
644
645
// Test card shipping
646
const shipped = await stripe.testHelpers.issuing.shipCard('ic_test_123');
647
648
// Test authorization capture
649
const captured = await stripe.testHelpers.issuing.capture('iauth_test_123', {
650
capture_amount: 1000
651
});
652
653
// Test authorization expiry
654
const expired = await stripe.testHelpers.issuing.expire('iauth_test_123');
655
656
// Test authorization increment
657
const incremented = await stripe.testHelpers.issuing.increment('iauth_test_123', {
658
increment_amount: 500,
659
is_amount_controllable: true
660
});
661
662
// Test authorization reversal
663
const reversed = await stripe.testHelpers.issuing.reverse('iauth_test_123', {
664
reverse_amount: 2000
665
});
666
667
// Test transaction creation (force capture)
668
const forceCapture = await stripe.testHelpers.issuing.createForceCapture({
669
card: 'ic_test_123',
670
amount: 3000,
671
currency: 'usd',
672
merchant_data: {
673
category: 'restaurants',
674
name: 'Test Restaurant',
675
network_id: 'test_merchant_123'
676
}
677
});
678
679
// Test unlinked refund
680
const unlinkedRefund = await stripe.testHelpers.issuing.createUnlinkedRefund({
681
card: 'ic_test_123',
682
amount: 1500,
683
currency: 'usd'
684
});
685
686
// Test transaction refund
687
const refunded = await stripe.testHelpers.issuing.refund('ipi_test_123', {
688
refund_amount: 1000
689
});
690
```
691
692
## Integration Examples
693
694
### Real-time Authorization Control
695
696
```typescript { .api }
697
// Webhook handler for authorization requests
698
app.post('/issuing-webhook', async (req, res) => {
699
const event = req.body;
700
701
if (event.type === 'issuing_authorization.request') {
702
const authorization = event.data.object;
703
704
// Custom authorization logic
705
const shouldApprove = await evaluateAuthorization(authorization);
706
707
if (shouldApprove) {
708
await stripe.issuing.authorizations.approve(authorization.id);
709
} else {
710
await stripe.issuing.authorizations.decline(authorization.id, {
711
reason: 'spending_controls'
712
});
713
}
714
}
715
716
res.status(200).send('OK');
717
});
718
719
async function evaluateAuthorization(auth) {
720
// Check spending limits
721
const monthlySpend = await getMonthlySpending(auth.card);
722
if (monthlySpend + auth.amount > MONTHLY_LIMIT) {
723
return false;
724
}
725
726
// Check merchant category
727
const blockedCategories = ['gambling', 'adult_digital_goods'];
728
if (blockedCategories.includes(auth.merchant_data.category)) {
729
return false;
730
}
731
732
// Check business hours for certain categories
733
if (auth.merchant_data.category === 'restaurants') {
734
const businessHours = isBusinessHours();
735
return businessHours;
736
}
737
738
return true;
739
}
740
```
741
742
### Expense Management Integration
743
744
```typescript { .api }
745
// Create cards for expense categories
746
const travelCard = await stripe.issuing.cards.create({
747
cardholder: 'ich_employee_123',
748
currency: 'usd',
749
type: 'virtual',
750
spending_controls: {
751
allowed_categories: [
752
'airlines',
753
'car_rental',
754
'lodging',
755
'restaurants'
756
],
757
spending_limits: [{
758
amount: 200000, // $2,000 monthly travel budget
759
interval: 'monthly'
760
}]
761
},
762
metadata: {
763
expense_category: 'travel',
764
employee_id: 'emp_123'
765
}
766
});
767
768
// Monitor transactions for expense reporting
769
const transactions = await stripe.issuing.transactions.list({
770
card: travelCard.id
771
});
772
773
for (const transaction of transactions.data) {
774
await createExpenseEntry({
775
employee_id: transaction.metadata?.employee_id,
776
category: transaction.merchant_data.category,
777
amount: transaction.amount,
778
merchant: transaction.merchant_data.name,
779
date: new Date(transaction.created * 1000)
780
});
781
}
782
```
783
784
## Type Definitions
785
786
```typescript { .api }
787
interface Address {
788
/** City/District/Suburb/Town/Village */
789
city: string | null;
790
/** 2-letter country code */
791
country: string | null;
792
/** Address line 1 (Street address/PO Box/Company name) */
793
line1: string | null;
794
/** Address line 2 (Apartment/Suite/Unit/Building) */
795
line2: string | null;
796
/** ZIP or postal code */
797
postal_code: string | null;
798
/** State/County/Province/Region */
799
state: string | null;
800
}
801
802
interface FlightDetails {
803
/** The time that the flight departed */
804
departure_at: number | null;
805
/** The name of the passenger */
806
passenger_name: string | null;
807
/** Whether the ticket is refundable */
808
refundable: boolean | null;
809
/** The legs of the trip */
810
segments: Array<{
811
/** The three-letter IATA airport code of the flight's destination */
812
arrival_airport_code: string | null;
813
/** The airline carrier code */
814
carrier: string | null;
815
/** The three-letter IATA airport code that the flight departed from */
816
departure_airport_code: string | null;
817
/** The flight number */
818
flight_number: string | null;
819
/** The flight's service class */
820
service_class: string | null;
821
/** Whether a stopover is allowed on this flight */
822
stopover_allowed: boolean | null;
823
}> | null;
824
/** The travel agency that issued the ticket */
825
travel_agency: string | null;
826
}
827
828
interface FuelDetails {
829
/** Conexxus Payment System Product Code identifying the primary fuel product purchased */
830
industry_product_code: string | null;
831
/** The quantity of units of fuel that was dispensed, represented as a decimal string with at most 12 decimal places */
832
quantity_decimal: string | null;
833
/** The type of fuel that was purchased. One of 'diesel', 'unleaded_plus', 'unleaded_regular', 'unleaded_super', or 'other' */
834
type: string;
835
/** The units for quantity_decimal. One of 'charging_minute', 'imperial_gallon', 'kilogram', 'kilowatt_hour', 'liter', 'pound', 'us_gallon', or 'other' */
836
unit: string;
837
/** The cost in cents per each unit of fuel, represented as a decimal string with at most 12 decimal places */
838
unit_cost_decimal: string;
839
}
840
841
interface LodgingDetails {
842
/** The time of checking into the lodging */
843
check_in_at: number | null;
844
/** The number of nights stayed at the lodging */
845
nights: number | null;
846
}
847
848
interface ReceiptDetails {
849
/** The description of the item. The maximum length of this field is 26 characters */
850
description: string | null;
851
/** The quantity of the item */
852
quantity: number | null;
853
/** The total for this line item in cents */
854
total: number | null;
855
/** The unit cost of the item in cents */
856
unit_cost: number | null;
857
}
858
```
859
860
Stripe Issuing provides a complete card issuing platform with sophisticated controls, real-time monitoring, and comprehensive dispute management capabilities for modern corporate card programs.