⚠️ Ce n'est PAS l'API cloud Viva
This is NOT the Viva cloud API
Modèle peer-to-peer (P2P), sans authentification. Ce SDK ne communique pas avec
api.vivapayments.com. Il parle directement au terminal de carte sur votre
réseau local, en adressant l'adresse IP et le port du terminal lui-même.
— Peer-to-peer (P2P), no authentication. This SDK talks directly to the card terminal on your LAN.
API cloud Viva
Local Terminal API (ce SDK)
Base URL
https://api.vivapayments.com
https://<ip-terminal>:<port>
Réseau
Internet
Réseau local (LAN), P2P
Authentification
OAuth2 / Basic / Bearer
Aucune — pas de header Authorization
TLS
CA publique
Certificat auto-signé du terminal
Erreurs 400
JSON structuré
Chaîne brute (texte du terminal verbatim)
Spec officielle : « In a closed network environment, authentication is not required for peer-to-peer
communication. [...] eliminating the need to include an Authorization tag in the header. »
Modèle asynchrone (polling)
Les opérations de transaction (sale, refund, capturePreauth…)
résolvent immédiatement un state (typiquement PROCESSING) et un
sessionId. Vous générez vous-même le sessionId (UUID), puis vous
interrogez terminal.sessions.get(sessionId) jusqu'à SUCCESS ou FAILURE
(champ payloadData renseigné).
Prérequis réseau
L'hôte exécutant votre code et le terminal doivent être sur le même LAN.
Vous devez connaître l'IP et le port du terminal (app Viva.com Terminal, réseau, ou zeroconf/mDNS).
Le terminal sert du HTTPS, généralement avec un certificat auto-signé — voir TLS.
Installation
Installez le SDK via npm / pnpm. Requiert Node 18+ (ou tout runtime avec fetch global : navigateurs, Deno).
Install via npm / pnpm. Requires Node 18+ (or any runtime with a global fetch).
npm install @qrcommunication/viva-local-terminal-sdk
# ou
pnpm add @qrcommunication/viva-local-terminal-sdk
Publié en ESM + CJS avec types .d.ts.
Démarrage rapideQuick Start
import { VivaLocalTerminalClient } from "@qrcommunication/viva-local-terminal-sdk";
import { randomUUID } from "node:crypto";
// 1. Pointer le client sur l'IP + port du terminal sur le LAN
const terminal = new VivaLocalTerminalClient({
terminalBaseUrl: "https://192.168.1.50:8080", // IP + port du terminal
verifyTls: false, // certificat auto-signé sur LAN fermé
});
// 2. Démarrer une vente (montant en centimes) — vous générez le sessionId
const sessionId = randomUUID();
const res = await terminal.transactions.sale({
sessionId,
amount: 1170, // 11,70 EUR
currencyCode: 978, // EUR
merchantReference: "order-123",
});
// res.state === "PROCESSING"
// 3. Interroger le résultat une fois le client ayant payé
const session = await terminal.sessions.get(sessionId);
// session.state === "SUCCESS" une fois la carte traitée
// 4. Contrôler le terminal
await terminal.device.screenControl(true);
await terminal.device.brightness(0.5);
Configuration
Le constructeur reçoit un objet d'options et n'accepte aucun identifiant
(pas de clé API, client ID ou secret) — le modèle P2P est sans authentification.
The constructor takes an options object and accepts no credentials — the P2P model is unauthenticated.
Option
Type
Défaut
Description
terminalBaseUrl
string
requis
URL de base : scheme + IP + port (ex : https://192.168.1.50:8080). Scheme obligatoire.
verifyTls
boolean
true
false désactive la vérification (cert auto-signé sur LAN fermé).
useIsvEndpoints
boolean
false
Cible les variantes ISV (chemins à slash final, ex : /pos/v1/sale/).
timeout
number
30000
Timeout par requête (millisecondes).
fetch
typeof fetch
global
Implémentation fetch personnalisée (tests).
dispatcher
Dispatcher
—
Dispatcher undici. Omis + verifyTls: false → Agent undici avec rejectUnauthorized: false créé automatiquement.
Le terminal sert du HTTPS, le plus souvent avec un certificat auto-signé.
// 1. Vérification standard (CA système) — défaut. Échoue sur cert auto-signé.
const terminal = new VivaLocalTerminalClient({
terminalBaseUrl: "https://192.168.1.50:8080",
});
// 2. Désactiver la vérification (modèle de confiance LAN-only)
// Sur Node, un Agent undici avec rejectUnauthorized: false est attaché automatiquement.
const terminal = new VivaLocalTerminalClient({
terminalBaseUrl: "https://192.168.1.50:8080",
verifyTls: false,
});
// 3. Contrôle fin : fournir votre propre Dispatcher undici (ex : CA pinné)
import { Agent } from "undici";
const terminal = new VivaLocalTerminalClient({
terminalBaseUrl: "https://192.168.1.50:8080",
dispatcher: new Agent({ connect: { ca: myTerminalCaPem } }),
});
Sur les runtimes sans undici (navigateur), verifyTls dépend du comportement de
fetch de la plateforme.
Ressources
1
Transactions
terminal.transactions
Opérations de transaction. Chaque opération résout immédiatementstate + sessionId ; interroger sessions.get() pour le résultat
final. Montants toujours en centimes.
Transaction operations. Each resolves immediately with state + sessionId; poll sessions.get() for the outcome. Amounts in cents.
Action de contrôle AADE FIM (fiscalisation grecque) — POST /pos/v1/aade-fim-control.
Crée l'Echo Message + le Control Message et valide la Master Key, le KCV et la Session Key chiffrée.
Lister les transactions historiques avec filtres optionnels — GET /pos/v1/transactions.
transactionTypes accepte un id unique ou un tableau (envoyé séparé par virgules).
import { TransactionTypeId } from "@qrcommunication/viva-local-terminal-sdk";
const result = await terminal.transactions.retrieve({
transactionTypes: [TransactionTypeId.SALE, TransactionTypeId.REFUND],
startDate: "2026-03-01T00:00:00Z",
endDate: "2026-03-31T23:59:59Z",
});
for (const txn of result.transactions ?? []) {
console.log(txn.orderCode);
}
2
Sessions
terminal.sessions
Récupération de session (polling). Après qu'une opération a retourné PROCESSING, interrogez
la session pour le résultat final. payloadData n'est renseigné qu'une fois la transaction
terminée (SUCCESS/FAILURE).
get(sessionId: string): Promise<SessionResponse>
Récupérer le détail d'une session — GET /pos/v1/sessions/{sessionId}.
Erreurs 400 = chaînes brutes. La Local Terminal API ne retourne pas de codes d'erreur
structurés. Sur une 400, elle renvoie un corps en chaîne de caractères brute
(ex : "ZeroconfException error message Amount cannot be null"). Le SDK préserve ce texte verbatim
dans ApiError.message.
— 400 errors are raw strings, not JSON. Preserved verbatim in ApiError.message.
Error
└── VivaError (base de toute erreur SDK)
└── ApiError (levée sur 4xx/5xx ET sur terminal injoignable : httpStatus === 0)
Membre
Type
Description
message
string
Texte d'erreur — chaîne brute du terminal verbatim sur 400
httpStatus
number
Code HTTP (0 si le terminal est injoignable)
responseBody
VivaErrorBody | null
Corps d'erreur ; chaîne brute préservée sous { raw: "..." }
getErrorText()
string | null
message, error, puis fallback sur raw
import { ApiError } from "@qrcommunication/viva-local-terminal-sdk";
try {
const res = await terminal.transactions.sale({ sessionId, amount: 1170 });
} catch (err) {
if (err instanceof ApiError) {
console.log(err.httpStatus); // 400, ou 0 si injoignable sur le LAN
console.log(err.getErrorText()); // ex: "ZeroconfException error message Amount cannot be null"
console.log(err.responseBody?.raw); // chaîne brute du terminal (si 400 non-JSON)
if (err.httpStatus === 0) {
// Terminal injoignable — vérifier IP/port/réseau
}
} else {
throw err;
}
}
Variantes Merchant vs ISV
Merchant vs ISV variants
Chaque endpoint existe en deux variantes : merchant (sans slash final) et
ISV (avec slash final, ex : /pos/v1/sale/). Un seul jeu de méthodes +
le toggle global useIsvEndpoints gère les deux.