0
# Terminal
1
2
Stripe Terminal enables in-person payment processing through certified card readers. This system provides comprehensive support for physical point-of-sale transactions, including chip cards, contactless payments, and mobile wallets across various reader types.
3
4
## Terminal Configuration
5
6
### Terminal.Configurations
7
8
Manage reader configurations and settings:
9
10
```typescript { .api }
11
interface TerminalConfiguration {
12
id: string;
13
object: 'terminal.configuration';
14
name?: string;
15
bbpos_wisepos_e?: {
16
splashscreen?: string;
17
};
18
offline?: {
19
enabled: boolean;
20
};
21
reboot_window?: {
22
end_hour: number;
23
start_hour: number;
24
};
25
stripe_s700?: {
26
splashscreen?: string;
27
};
28
tipping?: {
29
aud?: CurrencyTippingConfig;
30
cad?: CurrencyTippingConfig;
31
chf?: CurrencyTippingConfig;
32
czk?: CurrencyTippingConfig;
33
dkk?: CurrencyTippingConfig;
34
eur?: CurrencyTippingConfig;
35
gbp?: CurrencyTippingConfig;
36
hkd?: CurrencyTippingConfig;
37
myr?: CurrencyTippingConfig;
38
nok?: CurrencyTippingConfig;
39
nzd?: CurrencyTippingConfig;
40
pln?: CurrencyTippingConfig;
41
sek?: CurrencyTippingConfig;
42
sgd?: CurrencyTippingConfig;
43
usd?: CurrencyTippingConfig;
44
};
45
verifone_p400?: {
46
splashscreen?: string;
47
};
48
}
49
50
interface CurrencyTippingConfig {
51
fixed_amounts?: number[];
52
percentages?: number[];
53
smart_tip_threshold?: number;
54
}
55
56
// Create basic configuration
57
const configuration = await stripe.terminal.configurations.create({
58
name: 'Store Front Configuration',
59
tipping: {
60
usd: {
61
fixed_amounts: [100, 150, 200], // $1, $1.50, $2
62
percentages: [15, 18, 20],
63
smart_tip_threshold: 1000 // $10 threshold for smart tips
64
}
65
},
66
offline: {
67
enabled: true
68
},
69
reboot_window: {
70
start_hour: 2, // 2 AM
71
end_hour: 4 // 4 AM
72
}
73
});
74
75
// Create configuration with custom splash screen
76
const customConfig = await stripe.terminal.configurations.create({
77
name: 'Restaurant Configuration',
78
bbpos_wisepos_e: {
79
splashscreen: 'file_restaurant_logo'
80
},
81
stripe_s700: {
82
splashscreen: 'file_restaurant_logo'
83
},
84
tipping: {
85
usd: {
86
fixed_amounts: [200, 300, 500], // $2, $3, $5
87
percentages: [18, 20, 22],
88
smart_tip_threshold: 2000 // $20 threshold
89
}
90
}
91
});
92
93
// Retrieve configuration
94
const retrieved = await stripe.terminal.configurations.retrieve('tconf_123');
95
96
// Update configuration
97
const updated = await stripe.terminal.configurations.update('tconf_123', {
98
name: 'Updated Store Configuration',
99
tipping: {
100
usd: {
101
fixed_amounts: [150, 250, 350],
102
percentages: [15, 20, 25]
103
}
104
}
105
});
106
107
// List configurations
108
const configurations = await stripe.terminal.configurations.list({
109
limit: 10
110
});
111
112
// Delete configuration
113
const deleted = await stripe.terminal.configurations.del('tconf_123');
114
```
115
116
## Location Management
117
118
### Terminal.Locations
119
120
Manage physical locations where readers operate:
121
122
```typescript { .api }
123
interface TerminalLocation {
124
id: string;
125
object: 'terminal.location';
126
display_name?: string;
127
address: {
128
city?: string;
129
country: string;
130
line1?: string;
131
line2?: string;
132
postal_code?: string;
133
state?: string;
134
};
135
configuration_overrides?: string;
136
metadata?: { [key: string]: string };
137
}
138
139
// Create location
140
const location = await stripe.terminal.locations.create({
141
display_name: 'Main Store Location',
142
address: {
143
line1: '123 Main Street',
144
line2: 'Suite 100',
145
city: 'San Francisco',
146
state: 'CA',
147
postal_code: '94105',
148
country: 'US'
149
},
150
metadata: {
151
store_id: 'store_001',
152
manager: 'John Doe'
153
}
154
});
155
156
// Create location with configuration override
157
const restaurantLocation = await stripe.terminal.locations.create({
158
display_name: 'Downtown Restaurant',
159
address: {
160
line1: '456 Restaurant Row',
161
city: 'New York',
162
state: 'NY',
163
postal_code: '10001',
164
country: 'US'
165
},
166
configuration_overrides: 'tconf_restaurant_config'
167
});
168
169
// Retrieve location
170
const retrieved = await stripe.terminal.locations.retrieve('tml_123');
171
172
// Update location
173
const updated = await stripe.terminal.locations.update('tml_123', {
174
display_name: 'Updated Store Name',
175
metadata: {
176
store_id: 'store_001',
177
manager: 'Jane Smith',
178
last_updated: new Date().toISOString()
179
}
180
});
181
182
// List locations
183
const locations = await stripe.terminal.locations.list({
184
limit: 20
185
});
186
187
// Delete location
188
const deleted = await stripe.terminal.locations.del('tml_123');
189
```
190
191
## Reader Management
192
193
### Terminal.Readers
194
195
Manage and control card readers:
196
197
```typescript { .api }
198
interface TerminalReader {
199
id: string;
200
object: 'terminal.reader';
201
device_type: 'bbpos_wisepad3' | 'bbpos_wisepos_e' | 'simulated_wisepos_e' | 'stripe_m2' | 'stripe_s700' | 'verifone_p400' | 'mobile_phone_reader';
202
label?: string;
203
location?: string;
204
serial_number: string;
205
status: 'online' | 'offline';
206
device_sw_version?: string;
207
ip_address?: string;
208
base_url?: string;
209
registration_code?: string;
210
action?: {
211
type: 'process_payment_intent' | 'process_setup_intent' | 'set_reader_display';
212
status: 'in_progress' | 'succeeded' | 'failed';
213
failure_code?: string;
214
failure_message?: string;
215
process_payment_intent?: {
216
payment_intent: string;
217
process_config?: {
218
skip_tipping?: boolean;
219
tipping?: TippingConfiguration;
220
};
221
};
222
process_setup_intent?: {
223
setup_intent: string;
224
process_config?: {
225
customer_cancellation?: boolean;
226
};
227
};
228
};
229
}
230
231
// Register new reader
232
const reader = await stripe.terminal.readers.create({
233
registration_code: 'simulated-wpe',
234
label: 'Front Desk Reader',
235
location: 'tml_main_store'
236
});
237
238
// Register reader with specific device type
239
const physicalReader = await stripe.terminal.readers.create({
240
registration_code: 'stripe-reader-12345',
241
label: 'Checkout Station 1',
242
location: 'tml_store_001',
243
metadata: {
244
station_number: '1',
245
cashier_terminal: 'pos_001'
246
}
247
});
248
249
// Retrieve reader
250
const retrieved = await stripe.terminal.readers.retrieve('tmr_123');
251
252
// Update reader
253
const updated = await stripe.terminal.readers.update('tmr_123', {
254
label: 'Updated Reader Label',
255
metadata: {
256
last_maintenance: new Date().toISOString(),
257
firmware_version: '1.2.3'
258
}
259
});
260
261
// List readers
262
const readers = await stripe.terminal.readers.list({
263
device_type: 'verifone_p400',
264
location: 'tml_123',
265
limit: 20
266
});
267
268
// List readers by status
269
const onlineReaders = await stripe.terminal.readers.list({
270
status: 'online'
271
});
272
273
// Delete reader
274
const deleted = await stripe.terminal.readers.del('tmr_123');
275
```
276
277
## Payment Processing
278
279
### Process PaymentIntent
280
281
Handle in-person payments through terminal readers:
282
283
```typescript { .api }
284
// Process payment with reader
285
const payment = await stripe.terminal.readers.processPaymentIntent(
286
'tmr_reader_123',
287
{
288
payment_intent: 'pi_payment_123',
289
process_config: {
290
skip_tipping: false,
291
tipping: {
292
amount_eligible: 2000, // $20 eligible for tipping
293
}
294
}
295
}
296
);
297
298
// Process payment with custom tipping
299
const tippedPayment = await stripe.terminal.readers.processPaymentIntent(
300
'tmr_reader_123',
301
{
302
payment_intent: 'pi_payment_456',
303
process_config: {
304
tipping: {
305
amount_eligible: 5000, // $50 eligible for tipping
306
fixed_amounts: [200, 300, 500], // $2, $3, $5
307
percentages: [15, 18, 20]
308
}
309
}
310
}
311
);
312
313
// Process payment without tipping
314
const noTipPayment = await stripe.terminal.readers.processPaymentIntent(
315
'tmr_reader_123',
316
{
317
payment_intent: 'pi_payment_789',
318
process_config: {
319
skip_tipping: true
320
}
321
}
322
);
323
```
324
325
### Process SetupIntent
326
327
Handle card setup for future payments:
328
329
```typescript { .api }
330
// Process setup intent for card on file
331
const setup = await stripe.terminal.readers.processSetupIntent(
332
'tmr_reader_123',
333
{
334
setup_intent: 'seti_setup_123',
335
process_config: {
336
customer_cancellation: true // Allow customer to cancel
337
}
338
}
339
);
340
341
// Process setup intent without customer cancellation
342
const restrictedSetup = await stripe.terminal.readers.processSetupIntent(
343
'tmr_reader_123',
344
{
345
setup_intent: 'seti_setup_456',
346
process_config: {
347
customer_cancellation: false
348
}
349
}
350
);
351
```
352
353
## Reader Display Control
354
355
### Set Reader Display
356
357
Control what appears on the reader screen:
358
359
```typescript { .api }
360
interface ReaderDisplayCart {
361
line_items: Array<{
362
description: string;
363
amount: number;
364
quantity: number;
365
}>;
366
tax?: number;
367
total: number;
368
currency: string;
369
}
370
371
// Display shopping cart
372
const cartDisplay = await stripe.terminal.readers.setReaderDisplay(
373
'tmr_reader_123',
374
{
375
type: 'cart',
376
cart: {
377
line_items: [
378
{
379
description: 'Coffee',
380
amount: 350, // $3.50
381
quantity: 2
382
},
383
{
384
description: 'Pastry',
385
amount: 250, // $2.50
386
quantity: 1
387
}
388
],
389
tax: 95, // $0.95
390
total: 1045, // $10.45
391
currency: 'usd'
392
}
393
}
394
);
395
396
// Clear display
397
const clearDisplay = await stripe.terminal.readers.setReaderDisplay(
398
'tmr_reader_123',
399
{
400
type: 'clear'
401
}
402
);
403
```
404
405
## Reader Actions
406
407
### Cancel Reader Action
408
409
Cancel ongoing reader operations:
410
411
```typescript { .api }
412
// Cancel current action on reader
413
const canceled = await stripe.terminal.readers.cancelAction('tmr_reader_123');
414
```
415
416
## Connection Management
417
418
### Terminal.ConnectionTokens
419
420
Create connection tokens for reader connectivity:
421
422
```typescript { .api }
423
interface TerminalConnectionToken {
424
object: 'terminal.connection_token';
425
secret: string;
426
}
427
428
// Create connection token
429
const connectionToken = await stripe.terminal.connectionTokens.create({
430
location: 'tml_store_location'
431
});
432
433
// Create connection token without location restriction
434
const globalToken = await stripe.terminal.connectionTokens.create();
435
```
436
437
## Test Helpers
438
439
### TestHelpers.Terminal
440
441
Simulate terminal scenarios in test mode:
442
443
```typescript { .api }
444
// Present payment method to reader
445
const presented = await stripe.testHelpers.terminal.presentPaymentMethod(
446
'tmr_simulated_reader'
447
);
448
449
// Simulate different card types
450
const visaPresented = await stripe.testHelpers.terminal.presentPaymentMethod(
451
'tmr_simulated_reader',
452
{
453
type: 'card_present',
454
card_present: {
455
number: '4242424242424242'
456
}
457
}
458
);
459
460
const contactlessPresented = await stripe.testHelpers.terminal.presentPaymentMethod(
461
'tmr_simulated_reader',
462
{
463
type: 'card_present',
464
card_present: {
465
number: '4000000000000002', // Declined card for testing
466
brand: 'visa'
467
}
468
}
469
);
470
```
471
472
## Integration Examples
473
474
### Complete Terminal Payment Flow
475
476
```typescript { .api }
477
// 1. Create payment intent
478
const paymentIntent = await stripe.paymentIntents.create({
479
amount: 2500, // $25.00
480
currency: 'usd',
481
payment_method_types: ['card_present'],
482
capture_method: 'manual' // For tip adjustment
483
});
484
485
// 2. Process payment on terminal
486
const terminalPayment = await stripe.terminal.readers.processPaymentIntent(
487
'tmr_reader_123',
488
{
489
payment_intent: paymentIntent.id,
490
process_config: {
491
tipping: {
492
amount_eligible: 2500,
493
percentages: [15, 18, 20, 25]
494
}
495
}
496
}
497
);
498
499
// 3. Wait for completion (via webhook or polling)
500
// Once completed, capture with tip if applicable
501
if (terminalPayment.status === 'succeeded') {
502
const finalPayment = await stripe.paymentIntents.capture(paymentIntent.id, {
503
amount_to_capture: terminalPayment.amount // Includes tip
504
});
505
}
506
```
507
508
### Point of Sale Integration
509
510
```typescript { .api }
511
class TerminalPOS {
512
private readerId: string;
513
514
constructor(readerId: string) {
515
this.readerId = readerId;
516
}
517
518
async processOrder(orderItems: OrderItem[], customerId?: string) {
519
// Calculate total
520
const subtotal = orderItems.reduce((sum, item) =>
521
sum + (item.price * item.quantity), 0
522
);
523
const tax = Math.round(subtotal * 0.0875); // 8.75% tax
524
const total = subtotal + tax;
525
526
// Display cart on reader
527
await stripe.terminal.readers.setReaderDisplay(this.readerId, {
528
type: 'cart',
529
cart: {
530
line_items: orderItems.map(item => ({
531
description: item.name,
532
amount: item.price,
533
quantity: item.quantity
534
})),
535
tax,
536
total,
537
currency: 'usd'
538
}
539
});
540
541
// Create payment intent
542
const paymentIntent = await stripe.paymentIntents.create({
543
amount: total,
544
currency: 'usd',
545
customer: customerId,
546
payment_method_types: ['card_present'],
547
metadata: {
548
order_items: JSON.stringify(orderItems),
549
subtotal: subtotal.toString(),
550
tax: tax.toString()
551
}
552
});
553
554
// Process payment
555
const result = await stripe.terminal.readers.processPaymentIntent(
556
this.readerId,
557
{
558
payment_intent: paymentIntent.id,
559
process_config: {
560
tipping: {
561
amount_eligible: subtotal,
562
percentages: [15, 18, 20]
563
}
564
}
565
}
566
);
567
568
return result;
569
}
570
571
async handleRefund(originalPaymentIntentId: string, amount?: number) {
572
const refund = await stripe.refunds.create({
573
payment_intent: originalPaymentIntentId,
574
amount: amount, // Partial refund if specified
575
reason: 'requested_by_customer'
576
});
577
578
return refund;
579
}
580
}
581
```
582
583
### Multi-location Terminal Management
584
585
```typescript { .api }
586
class TerminalManager {
587
async deployReadersToLocation(locationId: string, readerCount: number) {
588
const readers = [];
589
590
for (let i = 1; i <= readerCount; i++) {
591
const reader = await stripe.terminal.readers.create({
592
registration_code: `simulated-reader-${i}`,
593
label: `Station ${i}`,
594
location: locationId,
595
metadata: {
596
station_number: i.toString(),
597
deployment_date: new Date().toISOString()
598
}
599
});
600
601
readers.push(reader);
602
}
603
604
return readers;
605
}
606
607
async getLocationStatus(locationId: string) {
608
const readers = await stripe.terminal.readers.list({
609
location: locationId
610
});
611
612
const onlineCount = readers.data.filter(r => r.status === 'online').length;
613
const totalCount = readers.data.length;
614
615
return {
616
location: locationId,
617
total_readers: totalCount,
618
online_readers: onlineCount,
619
offline_readers: totalCount - onlineCount,
620
readers: readers.data
621
};
622
}
623
624
async updateAllReadersConfiguration(locationId: string, configId: string) {
625
const location = await stripe.terminal.locations.update(locationId, {
626
configuration_overrides: configId
627
});
628
629
return location;
630
}
631
}
632
```
633
634
### Real-time Reader Monitoring
635
636
```typescript { .api }
637
// Webhook handler for terminal events
638
app.post('/terminal-webhook', async (req, res) => {
639
const event = req.body;
640
641
switch (event.type) {
642
case 'terminal.reader.action_succeeded':
643
const successfulAction = event.data.object;
644
await handleSuccessfulPayment(successfulAction);
645
break;
646
647
case 'terminal.reader.action_failed':
648
const failedAction = event.data.object;
649
await handleFailedPayment(failedAction);
650
break;
651
652
default:
653
console.log(`Unhandled terminal event: ${event.type}`);
654
}
655
656
res.status(200).send('OK');
657
});
658
659
async function handleSuccessfulPayment(reader: TerminalReader) {
660
if (reader.action?.type === 'process_payment_intent') {
661
const paymentIntentId = reader.action.process_payment_intent?.payment_intent;
662
663
// Update order status, send receipt, etc.
664
await updateOrderStatus(paymentIntentId, 'paid');
665
await sendCustomerReceipt(paymentIntentId);
666
}
667
}
668
```
669
670
Stripe Terminal provides a comprehensive in-person payment processing solution with support for various reader types, flexible tipping configurations, and real-time transaction monitoring capabilities.