or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

billing.mdcheckout.mdconfiguration.mdcore-resources.mdidentity.mdindex.mdissuing.mdradar.mdsubscriptions.mdtax.mdterminal.mdtreasury.mdwebhooks.md

terminal.mddocs/

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.