@qrcommunication/viva-local-terminal-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,593 @@
1
+ import { Dispatcher } from 'undici';
2
+
3
+ /**
4
+ * Configuration for the Viva.com Local Terminal API.
5
+ *
6
+ * Unlike the Viva cloud APIs (api.vivapayments.com, OAuth2), the Local Terminal
7
+ * API is a PEER-TO-PEER (P2P) protocol: the client talks DIRECTLY to the EFT POS
8
+ * terminal over the local network. There is therefore:
9
+ *
10
+ * - NO cloud "environment" (demo/production) — the base URL is the terminal's
11
+ * own IP address and port, e.g. `https://192.168.1.50:8080`.
12
+ * - NO authentication. The official spec states verbatim:
13
+ * "In a closed network environment, authentication is not required for
14
+ * peer-to-peer communication. [...] eliminating the need to include an
15
+ * Authorization tag in the header."
16
+ *
17
+ * The terminal serves HTTPS, usually with a self-signed certificate. By default
18
+ * this SDK VERIFIES TLS. On a closed LAN with a self-signed terminal cert you
19
+ * typically pass `verifyTls: false` (accepting the LAN-only trust model).
20
+ */
21
+
22
+ interface VivaLocalTerminalConfigOptions {
23
+ /**
24
+ * The terminal's base URL: scheme + IP + port, e.g.
25
+ * `https://192.168.1.50:8080`. A trailing slash, if present, is stripped.
26
+ */
27
+ terminalBaseUrl: string;
28
+ /**
29
+ * TLS certificate verification.
30
+ *
31
+ * `true` (default) verifies the terminal's certificate against the system CA
32
+ * bundle. `false` disables verification, which is the common case for a
33
+ * self-signed terminal certificate on a trusted closed LAN.
34
+ */
35
+ verifyTls?: boolean;
36
+ /**
37
+ * Target the ISV (trailing-slash) endpoint variants, e.g. `/pos/v1/sale/`.
38
+ * The merchant (default) variants use no trailing slash.
39
+ */
40
+ useIsvEndpoints?: boolean;
41
+ /**
42
+ * Per-request timeout in milliseconds. Terminal interactions are async (they
43
+ * return PROCESSING immediately), so a short timeout is fine for the
44
+ * initiating call. Defaults to 30000 (30s).
45
+ */
46
+ timeout?: number;
47
+ /**
48
+ * Optional `fetch` implementation override (mainly for testing). Defaults to
49
+ * the platform global `fetch` (Node 18+, browsers, Deno).
50
+ */
51
+ fetch?: typeof fetch;
52
+ /**
53
+ * Optional undici `Dispatcher` override. When omitted and `verifyTls` is
54
+ * `false` on Node, an undici `Agent` with `connect.rejectUnauthorized = false`
55
+ * is created automatically so the self-signed terminal cert is accepted.
56
+ */
57
+ dispatcher?: Dispatcher;
58
+ }
59
+ /**
60
+ * Immutable runtime configuration for the Local Terminal client.
61
+ */
62
+ declare class VivaLocalTerminalConfig {
63
+ /** The normalized terminal base URL (no trailing slash). */
64
+ readonly baseUrl: string;
65
+ readonly verifyTls: boolean;
66
+ readonly useIsvEndpoints: boolean;
67
+ readonly timeout: number;
68
+ readonly fetch: typeof fetch;
69
+ readonly dispatcher: Dispatcher | undefined;
70
+ constructor(options: VivaLocalTerminalConfigOptions);
71
+ /**
72
+ * Build the absolute URL for a `/pos/v1/...` endpoint.
73
+ *
74
+ * The ISV variants of the endpoints differ only by a trailing slash. When
75
+ * {@link useIsvEndpoints} is true, a trailing slash is appended to the path
76
+ * (unless one is already present), matching the spec's `(ISV)` paths.
77
+ */
78
+ url(path: string): string;
79
+ }
80
+
81
+ interface HttpRequestOptions {
82
+ query?: Record<string, string | number | boolean | undefined | null>;
83
+ body?: unknown;
84
+ signal?: AbortSignal;
85
+ }
86
+ /**
87
+ * Low-level HTTP client for the Local Terminal (P2P) API.
88
+ *
89
+ * Transport model:
90
+ * - Requests go DIRECTLY to the terminal on the LAN (base URL = terminal
91
+ * IP:port). There is NO cloud endpoint.
92
+ * - NO authentication: no Authorization header, no token exchange. The
93
+ * terminal trusts any caller on the closed network (per the official spec).
94
+ * - HTTPS is served by the terminal, often with a self-signed certificate. On
95
+ * Node, when `verifyTls` is `false`, an undici `Agent` with
96
+ * `connect.rejectUnauthorized = false` is used so the self-signed cert is
97
+ * accepted (the standard `fetch` API has no per-call TLS toggle).
98
+ *
99
+ * Error model:
100
+ * The API returns JSON on 2xx but a PLAIN STRING body on 400 (e.g.
101
+ * "ZeroconfException error message Amount cannot be null"). This client
102
+ * decodes JSON when possible and preserves the raw string under `raw`
103
+ * otherwise. The thrown {@link ApiError}'s message is that raw text.
104
+ */
105
+ declare class HttpClient {
106
+ private readonly config;
107
+ private readonly dispatcher;
108
+ constructor(config: VivaLocalTerminalConfig);
109
+ get<T = unknown>(path: string, options?: Omit<HttpRequestOptions, "body">): Promise<T>;
110
+ post<T = unknown>(path: string, body?: unknown, options?: Omit<HttpRequestOptions, "body">): Promise<T>;
111
+ private request;
112
+ private buildUrl;
113
+ private decodeBody;
114
+ private buildException;
115
+ private mergeSignals;
116
+ }
117
+
118
+ /**
119
+ * Enumerations for the Viva.com Local Terminal API.
120
+ *
121
+ * These mirror the string/numeric values the terminal returns and accepts.
122
+ */
123
+ /**
124
+ * The `paymentMethod` accepted by the sale request — the payment method
125
+ * displayed to the user first by default. The user may still choose an
126
+ * alternative method on the terminal.
127
+ *
128
+ * @see /pos/v1/sale
129
+ */
130
+ declare enum PaymentMethod {
131
+ CARD_PRESENT = "CardPresent",
132
+ IRIS = "Iris"
133
+ }
134
+ /**
135
+ * The `state` value returned by the Local Terminal API.
136
+ *
137
+ * Returned immediately by sale/refund/abort/etc. (PROCESSING, BUSY_ERROR, ...)
138
+ * and as the terminal/session outcome by GET /pos/v1/sessions/{sessionId}
139
+ * (SUCCESS, FAILURE).
140
+ *
141
+ * @see /pos/v1/sale, /pos/v1/sessions/{sessionId}
142
+ */
143
+ declare enum SessionState {
144
+ /** The operation is in progress on the terminal. */
145
+ PROCESSING = "PROCESSING",
146
+ /** Another transaction is already in progress on the terminal. */
147
+ BUSY_ERROR = "BUSY_ERROR",
148
+ /** The terminal reported a server-side error. */
149
+ SERVER_ERROR = "SERVER_ERROR",
150
+ /** The given session id could not be found (abort). */
151
+ SESSION_NOT_FOUND_ERROR = "SESSION_NOT_FOUND_ERROR",
152
+ /** The transaction completed successfully (sessions outcome). */
153
+ SUCCESS = "SUCCESS",
154
+ /** The transaction completed with an error (sessions outcome). */
155
+ FAILURE = "FAILURE"
156
+ }
157
+ /**
158
+ * The `sessionType` returned by the Local Terminal API, indicating which kind
159
+ * of operation a session represents.
160
+ *
161
+ * @see /pos/v1/sale, /pos/v1/refund, /pos/v1/abort, /pos/v1/sessions/{sessionId}
162
+ */
163
+ declare enum SessionType {
164
+ /** A sale transaction. */
165
+ SALE = "SALE",
166
+ /** A capture (completion) of a pre-authorized sale. */
167
+ CAPTURE_PREAUTH = "CAPTURE_PREAUTH",
168
+ /** A refund / cancellation referencing an original transaction. */
169
+ CANCEL = "CANCEL",
170
+ /** An unreferenced refund (not linked to an original transaction). */
171
+ UNREFERENCED_REFUND = "UNREFERENCED_REFUND",
172
+ /** An abort of an in-progress SALE session. */
173
+ ABORT = "ABORT"
174
+ }
175
+ /**
176
+ * Transaction type identifiers returned in transaction / session payloads
177
+ * (`transactionTypeId`) and accepted as the `transactionTypes` query filter on
178
+ * GET /pos/v1/transactions.
179
+ *
180
+ * @see /pos/v1/transactions, /pos/v1/sessions/{sessionId}
181
+ */
182
+ declare enum TransactionTypeId {
183
+ SALE = 5,
184
+ REFUND = 4,
185
+ REVERSAL = 7,
186
+ IRIS_SALE = 60,
187
+ IRIS_REFUND = 61,
188
+ IRIS_VOID = 85
189
+ }
190
+
191
+ /**
192
+ * Immediate response returned by sale / capture / refund / abort operations.
193
+ *
194
+ * The terminal returns this synchronously with `state` typically `PROCESSING`.
195
+ * Poll {@link SessionResponse} via `sessions.get(sessionId)` for the outcome.
196
+ */
197
+ interface TransactionResponse {
198
+ /** Operation state, e.g. PROCESSING, BUSY_ERROR. */
199
+ state?: SessionState | string;
200
+ /** The kind of session created, e.g. SALE, CANCEL. */
201
+ sessionType?: SessionType | string;
202
+ /** The session id echoed back (the one you passed in). */
203
+ sessionId?: string;
204
+ [key: string]: unknown;
205
+ }
206
+ /**
207
+ * Full session details returned by GET /pos/v1/sessions/{sessionId}.
208
+ *
209
+ * `payloadData` is populated only once the transaction has completed (state
210
+ * SUCCESS or FAILURE).
211
+ */
212
+ interface SessionResponse {
213
+ state?: SessionState | string;
214
+ sessionType?: SessionType | string;
215
+ sessionId?: string;
216
+ /** Final transaction payload, present once the session has completed. */
217
+ payloadData?: Record<string, unknown>;
218
+ [key: string]: unknown;
219
+ }
220
+ /**
221
+ * Response to AADE FIM control creation (Greek fiscalisation).
222
+ *
223
+ * @see /pos/v1/aade-fim-control
224
+ */
225
+ interface AadeFimControlResponse {
226
+ status?: string;
227
+ message?: string;
228
+ [key: string]: unknown;
229
+ }
230
+ /**
231
+ * Response to historical transaction retrieval.
232
+ *
233
+ * @see /pos/v1/transactions
234
+ */
235
+ interface TransactionsListResponse {
236
+ isSuccess?: boolean;
237
+ transactions?: Array<Record<string, unknown>>;
238
+ [key: string]: unknown;
239
+ }
240
+ /**
241
+ * Generic device-operation response (`screenControl`, `brightness`).
242
+ *
243
+ * @see /pos/v1/awake-lock, /pos/v1/brightness
244
+ */
245
+ interface DeviceResponse {
246
+ isSuccess?: boolean;
247
+ [key: string]: unknown;
248
+ }
249
+
250
+ /**
251
+ * Device configuration operations on the Local Terminal (P2P) API.
252
+ *
253
+ * These control the physical terminal device directly: screen wake/sleep and
254
+ * display brightness.
255
+ *
256
+ * @see /pos/v1/awake-lock, /pos/v1/brightness
257
+ */
258
+ declare class Device {
259
+ private readonly http;
260
+ constructor(http: HttpClient);
261
+ /**
262
+ * Control the device screen / sleep mode — POST /pos/v1/awake-lock.
263
+ *
264
+ * @param wakeUpLock When `true`, the device wakes from sleep and the screen
265
+ * stays active until the user unlocks it. When `false`, the device reverts
266
+ * to its normal sleep behavior.
267
+ */
268
+ screenControl(wakeUpLock: boolean): Promise<DeviceResponse>;
269
+ /**
270
+ * Adjust the terminal app brightness — POST /pos/v1/brightness.
271
+ *
272
+ * @param brightness Value in the range (0, 1], where 1.00 is maximum
273
+ * brightness. A value of 0 is NOT allowed.
274
+ * @throws {RangeError} If `brightness` is not within (0, 1].
275
+ */
276
+ brightness(brightness: number): Promise<DeviceResponse>;
277
+ }
278
+
279
+ /**
280
+ * Session retrieval on the Local Terminal (P2P) API.
281
+ *
282
+ * After a sale/refund/preauth-completion returns `PROCESSING`, poll the session
283
+ * to obtain the final outcome. The `payloadData` field is populated only once
284
+ * the transaction has completed (with `state` SUCCESS or FAILURE).
285
+ *
286
+ * The ISV variant uses a trailing slash (`/pos/v1/sessions/{id}/`), handled
287
+ * automatically when `useIsvEndpoints` is enabled.
288
+ *
289
+ * @see /pos/v1/sessions/{sessionId}
290
+ */
291
+ declare class Sessions {
292
+ private readonly http;
293
+ constructor(http: HttpClient);
294
+ /**
295
+ * Retrieve a session's full details by its id —
296
+ * GET /pos/v1/sessions/{sessionId}.
297
+ */
298
+ get(sessionId: string): Promise<SessionResponse>;
299
+ }
300
+
301
+ /**
302
+ * Parameters for {@link Transactions.sale} — POST /pos/v1/sale.
303
+ *
304
+ * Amounts are ALWAYS integers in the currency's minor unit (cents).
305
+ */
306
+ interface SaleParams {
307
+ /** Caller-generated transaction session UUID. */
308
+ sessionId: string;
309
+ /** Amount to authorize, in cents. */
310
+ amount: number;
311
+ /** Free-text merchant reference. */
312
+ merchantReference?: string;
313
+ /** Free-text customer reference. */
314
+ customerTrns?: string;
315
+ /** Whether the payment is a pre-authorization. */
316
+ preauth?: boolean;
317
+ /** Tip amount in cents (not compatible with `preauth`). */
318
+ tipAmount?: number;
319
+ /** Default payment method shown first (e.g. "CardPresent"). */
320
+ paymentMethod?: PaymentMethod | string;
321
+ /** Whether to show the transaction result on screen. */
322
+ showTransactionResult?: boolean;
323
+ /** Whether to show the receipt and result on screen. */
324
+ showReceipt?: boolean;
325
+ /** ISO 4217 numeric currency code (merchant currency), e.g. 978 for EUR. */
326
+ currencyCode?: number;
327
+ /** Disable surcharge even on eligible cards. */
328
+ skipSurcharge?: boolean;
329
+ /** Base64-encoded JSON of extra acquirer metadata. */
330
+ saleToAcquirerData?: string;
331
+ /** Max instalments allowed (Greek merchants only). */
332
+ maxInstalments?: number;
333
+ /** AADE provider id (Greece). */
334
+ aadeProviderId?: string;
335
+ /** AADE provider signature data (Greece). */
336
+ aadeProviderSignatureData?: string;
337
+ /** AADE provider signature (Greece). */
338
+ aadeProviderSignature?: string;
339
+ /** AADE preloaded flag (Greece). */
340
+ aadePreloaded?: boolean;
341
+ /** AADE preloaded expiry duration (Greece). */
342
+ aadePreloadedDuration?: number;
343
+ /** Viva Fiscalisation object. */
344
+ fiscalisationData?: Record<string, unknown>;
345
+ /** ISV partner / fee / multi-merchant object (ISV endpoints only). */
346
+ isvDetails?: Record<string, unknown>;
347
+ }
348
+ /**
349
+ * Parameters for {@link Transactions.capturePreauth} —
350
+ * POST /pos/v1/preauth-completion.
351
+ */
352
+ interface CapturePreauthParams {
353
+ /** Caller-generated transaction session UUID. */
354
+ sessionId: string;
355
+ /** Amount to capture, in cents. */
356
+ amount: number;
357
+ /** Transaction id of the original pre-authorized sale. */
358
+ transactionId: string;
359
+ merchantReference?: string;
360
+ customerTrns?: string;
361
+ /** ISO 4217 numeric currency code. */
362
+ currencyCode?: number;
363
+ saleToAcquirerData?: string;
364
+ aadeProviderId?: string;
365
+ aadeProviderSignatureData?: string;
366
+ aadeProviderSignature?: string;
367
+ aadePreloaded?: boolean;
368
+ aadePreloadedDuration?: number;
369
+ }
370
+ /**
371
+ * Parameters for {@link Transactions.refund} — POST /pos/v1/refund.
372
+ *
373
+ * A referenced refund / cancellation linked to an original transaction.
374
+ */
375
+ interface RefundParams {
376
+ /** Caller-generated transaction session UUID. */
377
+ sessionId: string;
378
+ /** Amount to refund, in cents. */
379
+ amount: number;
380
+ /** Transaction id of the original sale to refund. */
381
+ transactionId: string;
382
+ /** Order code of the original sale. */
383
+ orderCode?: number;
384
+ /** Short order code (filter helper). */
385
+ shortOrderCode?: number;
386
+ merchantReference?: string;
387
+ customerTrns?: string;
388
+ currencyCode?: number;
389
+ showTransactionResult?: boolean;
390
+ showReceipt?: boolean;
391
+ /** ISO 8601 lower bound for locating the transaction. */
392
+ txnDateFrom?: string;
393
+ /** ISO 8601 upper bound for locating the transaction. */
394
+ txnDateTo?: string;
395
+ aadeProviderId?: string;
396
+ aadeProviderSignatureData?: string;
397
+ aadeProviderSignature?: string;
398
+ }
399
+ /**
400
+ * Parameters for {@link Transactions.unreferencedRefund} —
401
+ * POST /pos/v1/unreferenced-refund.
402
+ */
403
+ interface UnreferencedRefundParams {
404
+ /** Caller-generated transaction session UUID. */
405
+ sessionId: string;
406
+ /** Amount to refund, in cents. */
407
+ amount: number;
408
+ merchantReference?: string;
409
+ customerTrns?: string;
410
+ showTransactionResult?: boolean;
411
+ showReceipt?: boolean;
412
+ aadeProviderId?: string;
413
+ aadeProviderSignatureData?: string;
414
+ aadeProviderSignature?: string;
415
+ fiscalisationData?: Record<string, unknown>;
416
+ }
417
+ /**
418
+ * Filters for {@link Transactions.retrieve} — GET /pos/v1/transactions.
419
+ *
420
+ * All filters are optional. `transactionTypes` may be a single id or a list.
421
+ */
422
+ interface RetrieveTransactionsParams {
423
+ cardNumber?: string;
424
+ orderCode?: string;
425
+ transactionTypes?: TransactionTypeId | number | Array<TransactionTypeId | number>;
426
+ transactionStatus?: string;
427
+ /** ISO 8601 lower bound. */
428
+ startDate?: string;
429
+ /** ISO 8601 upper bound. */
430
+ endDate?: string;
431
+ isAadeAutonomouslyOnly?: boolean;
432
+ }
433
+
434
+ /**
435
+ * Transaction operations on the Local Terminal (P2P) API.
436
+ *
437
+ * Every operation that starts a transaction returns IMMEDIATELY with a `state`
438
+ * (typically `PROCESSING`) and a `sessionId`. The actual outcome is then polled
439
+ * via `sessions.get()` once the cardholder has interacted with the terminal.
440
+ *
441
+ * Amounts are ALWAYS integers in the currency's minor unit (cents).
442
+ *
443
+ * Merchant vs ISV variants: the same methods serve both. Whether a request hits
444
+ * the ISV trailing-slash path (e.g. `/pos/v1/sale/`) is controlled globally by
445
+ * `useIsvEndpoints`. ISV sale/refund additionally accept `isvDetails`.
446
+ *
447
+ * @see /pos/v1/sale, /pos/v1/preauth-completion, /pos/v1/refund,
448
+ * /pos/v1/unreferenced-refund, /pos/v1/abort, /pos/v1/aade-fim-control,
449
+ * /pos/v1/transactions
450
+ */
451
+ declare class Transactions {
452
+ private readonly http;
453
+ constructor(http: HttpClient);
454
+ /**
455
+ * Initiate a sale request — POST /pos/v1/sale.
456
+ *
457
+ * The terminal displays the amount and waits for the card. Use
458
+ * `sessions.get()` with the returned `sessionId` to retrieve the final result.
459
+ */
460
+ sale(params: SaleParams): Promise<TransactionResponse>;
461
+ /**
462
+ * Capture (complete) a previously pre-authorized sale —
463
+ * POST /pos/v1/preauth-completion.
464
+ */
465
+ capturePreauth(params: CapturePreauthParams): Promise<TransactionResponse>;
466
+ /**
467
+ * Refund / cancel a transaction by its original transaction id —
468
+ * POST /pos/v1/refund.
469
+ */
470
+ refund(params: RefundParams): Promise<TransactionResponse>;
471
+ /**
472
+ * Issue an unreferenced refund (not linked to an original transaction) —
473
+ * POST /pos/v1/unreferenced-refund.
474
+ */
475
+ unreferencedRefund(params: UnreferencedRefundParams): Promise<TransactionResponse>;
476
+ /**
477
+ * Abort an in-progress SALE session — POST /pos/v1/abort.
478
+ */
479
+ abort(sessionId: string): Promise<TransactionResponse>;
480
+ /**
481
+ * Create an AADE FIM control action — POST /pos/v1/aade-fim-control.
482
+ *
483
+ * Creates the Echo Message (to fetch the Master Key) and the Control Message
484
+ * (to create the Session Key), validating the Master Key, KCV and encrypted
485
+ * Session Key (Greek AADE fiscalisation).
486
+ *
487
+ * @param token The FIMAS control token including the AADE token.
488
+ */
489
+ aadeFimControl(token: string): Promise<AadeFimControlResponse>;
490
+ /**
491
+ * Retrieve historical transactions with optional filters —
492
+ * GET /pos/v1/transactions.
493
+ *
494
+ * `transactionTypes` may be a single id or a list. When an array is passed it
495
+ * is sent as a comma-separated value.
496
+ */
497
+ retrieve(params?: RetrieveTransactionsParams): Promise<TransactionsListResponse>;
498
+ }
499
+
500
+ type VivaLocalTerminalClientOptions = VivaLocalTerminalConfigOptions;
501
+ /**
502
+ * Viva.com Local Terminal SDK — main entry point.
503
+ *
504
+ * The Local Terminal API is a PEER-TO-PEER (P2P) protocol: this client talks
505
+ * DIRECTLY to an EFT POS terminal over the local network. There is no Viva cloud
506
+ * endpoint and no authentication — you address the terminal's own IP and port.
507
+ *
508
+ * @example
509
+ * ```ts
510
+ * import { VivaLocalTerminalClient } from "@qrcommunication/viva-local-terminal-sdk";
511
+ * import { randomUUID } from "node:crypto";
512
+ *
513
+ * const terminal = new VivaLocalTerminalClient({
514
+ * terminalBaseUrl: "https://192.168.1.50:8080",
515
+ * // self-signed terminal cert on a closed LAN:
516
+ * verifyTls: false,
517
+ * });
518
+ *
519
+ * // Start a sale (amount in cents)
520
+ * const sessionId = randomUUID();
521
+ * const res = await terminal.transactions.sale({
522
+ * sessionId,
523
+ * amount: 1170, // 11.70 EUR
524
+ * currencyCode: 978, // EUR
525
+ * merchantReference: "order-123",
526
+ * });
527
+ * // res.state === "PROCESSING"
528
+ *
529
+ * // Poll for the result
530
+ * const session = await terminal.sessions.get(sessionId);
531
+ * // session.state === "SUCCESS" once the cardholder has paid
532
+ *
533
+ * // Control the device
534
+ * await terminal.device.screenControl(true);
535
+ * await terminal.device.brightness(0.5);
536
+ * ```
537
+ */
538
+ declare class VivaLocalTerminalClient {
539
+ readonly transactions: Transactions;
540
+ readonly sessions: Sessions;
541
+ readonly device: Device;
542
+ private readonly config;
543
+ private readonly http;
544
+ constructor(options: VivaLocalTerminalClientOptions);
545
+ /** The resolved, immutable configuration in use by this client. */
546
+ getConfig(): VivaLocalTerminalConfig;
547
+ }
548
+
549
+ /**
550
+ * Error model for the Viva.com Local Terminal (P2P) API.
551
+ *
552
+ * The Local Terminal API does NOT return structured error codes. On a 400 it
553
+ * returns a PLAIN STRING body (e.g. "ZeroconfException error message Amount
554
+ * cannot be null"). The raw body is always preserved so callers can inspect the
555
+ * exact text the terminal sent back.
556
+ */
557
+ /**
558
+ * Shape used to carry whatever the terminal returned on an error. When the body
559
+ * was JSON it is spread here; when it was a plain string it is preserved under
560
+ * `raw`.
561
+ */
562
+ interface VivaErrorBody {
563
+ message?: string;
564
+ error?: string;
565
+ /** The raw, undecoded response body (set when the terminal returns a string). */
566
+ raw?: string;
567
+ [key: string]: unknown;
568
+ }
569
+ /**
570
+ * Base error for every Viva Local Terminal SDK failure.
571
+ */
572
+ declare class VivaError extends Error {
573
+ constructor(message: string);
574
+ }
575
+ /**
576
+ * Thrown when the terminal returns an HTTP error (4xx/5xx) or when the request
577
+ * could not reach the terminal at all (httpStatus === 0).
578
+ *
579
+ * The Local Terminal API returns a plain string body on 400, so the human
580
+ * message is that raw string verbatim. Use {@link getErrorText} to retrieve it.
581
+ */
582
+ declare class ApiError extends VivaError {
583
+ readonly httpStatus: number;
584
+ readonly responseBody: VivaErrorBody | null;
585
+ constructor(message: string, httpStatus: number, responseBody?: VivaErrorBody | null);
586
+ /**
587
+ * The error text reported by the terminal, preferring a structured field and
588
+ * falling back to the raw string body. Returns `null` if nothing was sent.
589
+ */
590
+ getErrorText(): string | null;
591
+ }
592
+
593
+ export { type AadeFimControlResponse, ApiError, type CapturePreauthParams, Device, type DeviceResponse, HttpClient, type HttpRequestOptions, PaymentMethod, type RefundParams, type RetrieveTransactionsParams, type SaleParams, type SessionResponse, SessionState, SessionType, Sessions, type TransactionResponse, TransactionTypeId, Transactions, type TransactionsListResponse, type UnreferencedRefundParams, VivaError, type VivaErrorBody, VivaLocalTerminalClient, type VivaLocalTerminalClientOptions, VivaLocalTerminalConfig, type VivaLocalTerminalConfigOptions };