Riferimento API
Base: https://opentabacchi.org/v1. Tutte le risposte sono JSON con codifica UTF-8, salvo i file del dataset che sono gzip. Tutti gli esempi usano dati di fantasia.
Autenticazione
Ogni richiesta porta una chiave API (come ottenerla) in una di queste intestazioni:
Authorization: Bearer otb_la_tua_chiave
X-Api-Key: otb_la_tua_chiave
Senza chiave valida: 401, intestazione WWW-Authenticate: Bearer e corpo { "error": "invalid_api_key", "message": "Chiave API mancante o non valida." }.
Limiti e intestazioni
Le chiamate GET consumano una lettura ciascuna (10 al giorno per account, giorno UTC, anche quando rispondono 304). POST /v1/barcodes consuma invece il contatore degli invii (100 elementi all'ora, valore predefinito) e non tocca le letture. Ogni risposta riporta il contatore usato:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 8
X-RateLimit-Reset: 1792454400
Spiegazione completa e strategia di cache in Limiti e uso corretto.
Codici di stato ed errori
| Stato | Quando | Corpo |
|---|---|---|
200 | Richiesta eseguita. | JSON o file gzip. |
304 | Download con If-None-Match uguale all'ETag corrente. | Vuoto. Conta comunque come lettura. |
400 | Batch di barcode vuoto o troppo grande. | { "error": "empty_batch" } oppure { "error": "batch_too_large", "max": 500 } |
401 | Chiave mancante, non valida, revocata o account bloccato. | { "error": "invalid_api_key" } |
404 | Nessuna release ancora pubblicata (solo /version e i file). | { "error": "no_release", "message": "Nessuna release ancora pubblicata." } |
429 | Limite superato; intestazione Retry-After in secondi. | { "error": "rate_limited", "message": "…", "retryAfterSeconds": 3600 }; per gli invii anche limit e remaining. |
Gli errori hanno sempre un campo error con un codice stabile e, quando serve, un message in italiano destinato ai log, non all'utente finale.
/v1/version1 letturaIl manifest della release corrente. È la chiamata da fare una volta al giorno: se version coincide con quella già importata, non c'è altro da scaricare.
curl -H "Authorization: Bearer otb_la_tua_chiave" https://opentabacchi.org/v1/version
200
{
"version": "20261014.2",
"tariffDate": "2026-10-14",
"generatedAt": "2026-10-14T09:00:00+00:00",
"source": "Agenzia delle Dogane e dei Monopoli (ADM)",
"schemaVersion": 2,
"counts": { "products": 4343, "barcodes": 120 },
"files": {
"json": { "url": "https://opentabacchi.org/v1/dataset.json.gz", "sha256": "9f2c…", "size": 83912 },
"sqlite": { "url": "https://opentabacchi.org/v1/dataset.sqlite.gz", "sha256": "4b71…", "size": 161280 },
"blite": { "url": "https://opentabacchi.org/v1/dataset.blite.gz", "sha256": "c0de…", "size": 346112,
"bliteVersion": "5.2.3", "schemaVersion": 2 }
}
}
| Campo | Tipo | Significato |
|---|---|---|
version | stringa | AAAAMMGG.n: data della tariffa in vigore e progressivo. Cambia a ogni modifica dei dati pubblicati. |
tariffDate | data ISO | Data di decorrenza della tariffa in vigore. |
generatedAt | data e ora ISO 8601 | Quando la release è stata costruita. |
source | stringa | Sempre «Agenzia delle Dogane e dei Monopoli (ADM)». |
schemaVersion | intero | Versione della forma dei dati, uguale nei tre formati. Oggi 2. |
counts.products, counts.barcodes | interi | Righe presenti nei file. |
files.*.url, sha256, size | stringa, esadecimale, byte | URL assoluto, impronta e dimensione del file compresso. |
files.blite.bliteVersion | stringa | Versione del pacchetto BLite con cui è scritto il file: va aperto con la stessa. Vedi BLite. |
Se non è ancora stata pubblicata alcuna release: 404 con error: "no_release".
/v1/dataset.json.gz1 lettura/v1/dataset.sqlite.gz1 lettura/v1/dataset.blite.gz1 letturaIl dataset completo nel formato scelto, compresso con gzip (Content-Type: application/gzip, Content-Disposition: attachment; filename=opentabacchi-<versione>.<formato>.gz). I tre file hanno lo stesso contenuto; lo schema è in Formati e schema.
La risposta porta ETag: "<sha256>", cioè l'impronta del file tra virgolette. Inviando If-None-Match con quel valore si riceve 304 senza corpo quando il file è ancora lo stesso; la lettura viene consumata ugualmente.
curl -H "Authorization: Bearer otb_la_tua_chiave" \
-H 'If-None-Match: "9f2c…"' \
-o opentabacchi.sqlite.gz -w "%{http_code}\n" \
https://opentabacchi.org/v1/dataset.sqlite.gz
Verifica sempre lo SHA-256 del file ricevuto contro files.*.sha256 del manifest prima di importarlo.
/v1/barcodes1 invio per elementoPropone abbinamenti tra codice a barre e codice AAMS. Fino a 500 elementi per chiamata, entro il contatore orario degli invii. Un batch che supera i residui viene rifiutato per intero con 429. Le regole di approvazione sono in Codici a barre.
POST /v1/barcodes
Authorization: Bearer otb_la_tua_chiave
Content-Type: application/json
{
"items": [
{ "barcode": "4006381333931", "admCode": 12345 },
{ "barcode": "4006381333948", "admCode": 12345, "kind": "carton", "units": 10 }
]
}
| Campo | Obbligatorio | Valori |
|---|---|---|
barcode | sì | 8, 12, 13 o 14 cifre con cifra di controllo GS1 valida. |
admCode | sì | Codice AAMS intero, presente nella tariffa. |
kind | no | pack (predefinito) o carton. |
units | no | Pezzi per codice: 1 per pack (predefinito), da 2 a 1000 per carton. |
contributorRef | no | Solo per gli account di tipo integrazione: identificativo opaco del punto vendita (1–64 caratteri tra lettere, cifre, . _ : -). |
{
"accepted": 1, "unchanged": 0, "rejected": 1,
"results": [
{ "index": 0, "barcode": "4006381333931", "outcome": "accepted", "reason": null, "status": "to_confirm" },
{ "index": 1, "barcode": "4006381333948", "outcome": "rejected", "reason": "invalid_checksum", "status": null }
]
}
Per ogni elemento, nell'ordine inviato: outcome è accepted (segnalazione registrata o aggiornata), unchanged (avevi già inviato lo stesso abbinamento) o rejected; status è lo stato del codice a barre dopo l'elaborazione (to_confirm, approved, conflict, revoked) e manca per i rifiuti. Ogni account ha un solo voto per codice a barre: un nuovo invio sostituisce il precedente.
| Motivo del rifiuto | Significato |
|---|---|
invalid_barcode | Lunghezza o caratteri non ammessi (servono 8, 12, 13 o 14 cifre). |
invalid_checksum | La cifra di controllo non torna. |
unsupported_barcode | Prefisso EAN-13 di un altro tipo di codice: editoria (977, 978, 979), uso interno o peso variabile (2), buoni e rimborsi (98, 99). |
unknown_adm_code | Il codice AAMS non esiste nella tariffa. |
invalid_kind | kind diverso da pack o carton. |
invalid_units | units diverso da 1 per pack o fuori da 2–1000 per carton. |
barcode_revoked | L'amministratore ha revocato questo codice: non accetta più segnalazioni. |
contributor_ref_not_allowed | contributorRef inviato da un account che non è un'integrazione. |
invalid_contributor_ref | Formato di contributorRef non ammesso. |
contributor_blocked | Il contributore indicato è stato bloccato dall'amministratore. |
HTTP/1.1 429 Too Many Requests
Retry-After: 1800
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 30
{ "error": "rate_limited",
"message": "Limite orario di invii raggiunto: il batch non è stato elaborato.",
"limit": 100, "remaining": 30, "retryAfterSeconds": 1800 }
/v1/my-submissions1 letturaLe segnalazioni del tuo account, dalla più recente, con lo stato attuale del codice a barre. Parametri: limit (predefinito 500, massimo 1000) e offset.
curl -H "Authorization: Bearer otb_la_tua_chiave" "https://opentabacchi.org/v1/my-submissions?limit=100&offset=0"
200
{
"items": [
{ "barcode": "4006381333931", "admCode": 12345, "kind": "pack", "units": 1,
"contributorRef": null, "submittedAt": "2026-10-14T10:12:00+00:00", "status": "to_confirm" }
]
}
status vale to_confirm, approved, conflict, revoked oppure outvoted: il codice è stato approvato con un abbinamento diverso dal tuo (altro codice AAMS, tipo o numero di pezzi).
/v1/me1 letturaConferma la chiave e mostra i contatori. Costa una lettura come le altre: non usarla per «controllare prima» ogni chiamata.
200{
"email": "sviluppo@esempio.test",
"type": "User",
"limits": {
"read": { "period": "day", "limit": 10, "used": 2, "remaining": 8, "resetsAt": "2026-10-15T00:00:00+00:00" },
"submit": { "period": "hour", "limit": 100, "used": 0, "remaining": 100, "resetsAt": "2026-10-14T11:00:00+00:00" }
}
}
type è User, Supplier o Integration.