Guida all'utilizzo
Assicurati di aver configurato un bridge NoPos nell'app con protocollo NoPos e di avere l'IP locale della cassa. Vedi Introduzione.
GET /status
Verifica che il server sia raggiungibile e controlla quali provider sono configurati.
Request
curl http://192.168.1.100:5200/status
Response
{
"success": true,
"data": {
"version": "NOPOS/1.0",
"payment": true,
"fiscal": true
}
}
| Campo | Tipo | Descrizione |
|---|---|---|
version | string | Versione del protocollo |
payment | boolean | Provider di pagamento configurato |
fiscal | boolean | Provider fiscale configurato |
POST /payments
Avvia un pagamento sul terminale configurato nel bridge.
Request body
{
"amount": 25.50,
"currency": "EUR",
"description": "Ordine #1234"
}
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
amount | number | ✓ | Importo in euro (es. 25.50) |
currency | string | Valuta ISO 4217. Default: EUR | |
description | string | Descrizione visibile sul terminale | |
provider | string | Override del provider configurato nel bridge | |
terminalId | string | Override del terminale configurato nel bridge |
Response
{
"success": true,
"data": {
"id": "tx_abc123",
"status": "completed",
"amount": 25.50,
"currency": "EUR"
}
}
| Campo | Tipo | Descrizione |
|---|---|---|
id | string | ID della transazione |
status | string | pending · completed · failed · canceled · verification |
amount | number | Importo confermato |
currency | string | Valuta |
Il server risponde solo quando il pagamento ha raggiunto uno stato finale. Non è necessario fare polling: la risposta arriva quando l'utente ha interagito con il terminale.
- JavaScript
- Python
- PHP
const response = await fetch('http://192.168.1.100:5200/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 25.50,
currency: 'EUR',
description: 'Ordine #1234'
})
});
const { success, data, error } = await response.json();
if (!success) {
console.error('Pagamento fallito:', error);
} else {
console.log('Transazione:', data.id, '—', data.status);
}
import requests
res = requests.post('http://192.168.1.100:5200/payments', json={
'amount': 25.50,
'currency': 'EUR',
'description': 'Ordine #1234'
})
envelope = res.json()
if not envelope['success']:
raise Exception(envelope['error'])
tx = envelope['data']
print(f"Transazione: {tx['id']} — {tx['status']}")
<?php
$ch = curl_init('http://192.168.1.100:5200/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 25.50,
'currency' => 'EUR',
'description' => 'Ordine #1234',
]),
]);
$body = curl_exec($ch);
curl_close($ch);
$envelope = json_decode($body, true);
if (!$envelope['success']) {
throw new Exception($envelope['error']);
}
$tx = $envelope['data'];
echo "Transazione: {$tx['id']} — {$tx['status']}";
?>
POST /payments/refund
Rimborsa una transazione precedente, in tutto o in parte.
Request body
{
"transactionId": "tx_abc123",
"amount": 10.00
}
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
transactionId | string | ✓ | ID della transazione originale |
amount | number | Importo da rimborsare. Se assente, rimborso totale | |
provider | string | Override del provider |
Response — stessa shape di /payments.
POST /receipts
Emette uno scontrino fiscale tramite il provider fiscale configurato nel bridge.
Request body
{
"type": "sale",
"items": [
{
"description": "Pizza Margherita",
"quantity": 2,
"price": 8.50,
"vat": "22"
},
{
"description": "Acqua naturale",
"quantity": 1,
"price": 2.00,
"vat": "22"
}
],
"payment": {
"cash": 19.00
}
}
Campi type disponibili
| Valore | Descrizione |
|---|---|
sale | Vendita normale |
return | Annullo documento (reso) |
refund | Rimborso parziale |
Per return e refund passa original con l'ID dello scontrino da annullare.
Campi items
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
description | string | ✓ | Descrizione del prodotto |
quantity | number | ✓ | Quantità |
price | number | ✓ | Prezzo unitario in euro |
vat | string | ✓ | Aliquota IVA. Valori: 4 · 5 · 10 · 22 · N4 (esente) · N2 (non soggetto) · ecc. |
discount | number | Sconto sull'articolo in euro | |
gift | boolean | Articolo omaggio (prezzo = 0 in scontrino) |
Campi payment
| Campo | Tipo | Descrizione |
|---|---|---|
cash | number | Importo pagato in contanti |
electronic | number | Importo pagato con carta/POS |
ticket | number | Importo pagato con buoni pasto |
ticketCount | number | Numero di buoni pasto |
discount | number | Sconto applicato al totale |
credit | number | Importo a credito |
Altri campi del body
| Campo | Tipo | Descrizione |
|---|---|---|
lottery | string | Codice lotteria scontrini |
original | string | ID scontrino originale (per return / refund) |
provider | string | Override del provider fiscale |
Response
{
"success": true,
"data": {
"id": "rec_xyz789",
"status": "completed",
"number": "2026-0042",
"amount": 19.00
}
}
| Campo | Tipo | Descrizione |
|---|---|---|
id | string | ID del documento nel provider fiscale |
status | string | pending · completed · failed · canceled |
number | string | Numero progressivo del documento (se disponibile) |
amount | number | Importo totale del documento |
- JavaScript
- Python
- PHP
const response = await fetch('http://192.168.1.100:5200/receipts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'sale',
items: [
{ description: 'Pizza Margherita', quantity: 2, price: 8.50, vat: '22' },
{ description: 'Acqua naturale', quantity: 1, price: 2.00, vat: '22' },
],
payment: { cash: 19.00 }
})
});
const { success, data, error } = await response.json();
if (!success) {
console.error('Scontrino fallito:', error);
} else {
console.log('Scontrino n.', data.number, '— importo €', data.amount);
}
import requests
res = requests.post('http://192.168.1.100:5200/receipts', json={
'type': 'sale',
'items': [
{'description': 'Pizza Margherita', 'quantity': 2, 'price': 8.50, 'vat': '22'},
{'description': 'Acqua naturale', 'quantity': 1, 'price': 2.00, 'vat': '22'},
],
'payment': {'cash': 19.00},
})
envelope = res.json()
if not envelope['success']:
raise Exception(envelope['error'])
rec = envelope['data']
print(f"Scontrino n. {rec['number']} — importo €{rec['amount']}")
<?php
$ch = curl_init('http://192.168.1.100:5200/receipts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'sale',
'items' => [
['description' => 'Pizza Margherita', 'quantity' => 2, 'price' => 8.50, 'vat' => '22'],
['description' => 'Acqua naturale', 'quantity' => 1, 'price' => 2.00, 'vat' => '22'],
],
'payment' => ['cash' => 19.00],
]),
]);
$body = curl_exec($ch);
curl_close($ch);
$envelope = json_decode($body, true);
if (!$envelope['success']) {
throw new Exception($envelope['error']);
}
$rec = $envelope['data'];
echo "Scontrino n. {$rec['number']} — importo €{$rec['amount']}";
?>
POST /invoices
Emette una fattura elettronica tramite il provider fiscale configurato.
Request body
{
"type": "TD01",
"regime": "RF01",
"items": [
{
"description": "Consulenza sviluppo software",
"quantity": 8,
"price": 120.00,
"vat": "22.00"
}
],
"customer": {
"vatId": "IT12345678901",
"name": "Acme S.r.l.",
"pec": "acme@pec.it",
"address": {
"street": "Via Roma",
"number": "1",
"postal": "20100",
"city": "Milano",
"state": "MI",
"country": "IT"
}
},
"payment": {
"electronic": 1171.20
}
}
Campi type — tipo documento SDI (principali)
| Valore | Descrizione |
|---|---|
TD01 | Fattura |
TD04 | Nota di credito |
TD05 | Nota di debito |
TD06 | Parcella |
Campi regime — regime fiscale (principali)
| Valore | Descrizione |
|---|---|
RF01 | Ordinario |
RF19 | Forfettario (L. 190/2014) |
Campi items
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
description | string | ✓ | Descrizione |
quantity | number | ✓ | Quantità |
price | number | ✓ | Prezzo unitario |
vat | string | ✓ | Aliquota IVA con due decimali: 22.00 · 10.00 · 4.00 · 0.00 |
Campi customer
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
vatId | string | ✓ | Partita IVA o Codice Fiscale |
name | string | Denominazione (azienda) | |
firstName | string | Nome (persona fisica) | |
lastName | string | Cognome (persona fisica) | |
pec | string | Indirizzo PEC | |
sdi | string | Codice SDI (se assente, viene usata la PEC) | |
address | object | Indirizzo completo |
Response
{
"success": true,
"data": {
"id": "inv_def456",
"status": "pending",
"number": "2026/0015",
"amount": 1171.20
}
}
Le fatture elettroniche passano per lo SDI e possono rimanere in stato pending per alcuni minuti prima di diventare completed. Implementa il polling su /v1/fiscal/:providerId/invoices/:id tramite API NoPos se hai bisogno di tracciare il completamento.
Gestione degli errori
Ogni risposta con success: false include un campo error leggibile:
{
"success": false,
"error": "Pagamento non completato dal terminale"
}
Errori HTTP
| Codice | Situazione |
|---|---|
400 | Campi obbligatori mancanti nel body |
404 | Route non esistente |
500 | Errore interno (provider non raggiungibile, timeout, ecc.) |
Pattern consigliato
async function noposRequest(ip, path, body = null) {
const url = `http://${ip}:5200${path}`;
const options = {
method: body ? 'POST' : 'GET',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
...(body ? { body: JSON.stringify(body) } : {}),
};
const res = await fetch(url, options);
const envelope = await res.json();
if (!envelope.success) throw new Error(envelope.error);
return envelope.data;
}
// Utilizzo
const tx = await noposRequest('192.168.1.100', '/payments', { amount: 15.00 });
const rec = await noposRequest('192.168.1.100', '/receipts', {
type: 'sale',
items: [{ description: 'Caffè', quantity: 1, price: 1.50, vat: '22' }],
payment: { cash: 2.00 },
});