Guida all'API degli identificatori
Un identificatore collega una marcatura fisica a una Scheda: un identificatore DUST, un codice QR, un codice a barre, un simbolo Data Matrix, un chip NFC o un codice testuale stampato. Una volta associato, una scansione sul campo viene risolta nel registro digitale. Lo spazio dei nomi dell’API è /api/v1/tags: una denominazione legacy che permane nei percorsi e negli schemi; nella prosa, questa documentazione usa identificatore.
Schemi completi di richiesta/risposta: riferimento API. Ogni esito che ciascuna operazione può produrre, inclusi quelli restituiti come errori HTTP, è riportato una sola volta in Errori ed esiti delle scansioni.
Panoramica delle operazioni
Sezione intitolata “Panoramica delle operazioni”| Operazione | Metodo e percorso | Semantica |
|---|---|---|
| Estrai | POST /api/v1/tags/extract | Analizza un’acquisizione DUST per ottenere un’impronta canonica, senza associarla |
| Associa | POST /api/v1/tags/bind | Associa un identificatore a una Scheda |
| Identifica | POST /api/v1/tags/identify | Cerca: quale Scheda corrisponde a questa scansione? |
| Verifica | POST /api/v1/tags/verify | Confronta una scansione con gli identificatori di una Scheda specifica |
| Dissocia | POST /api/v1/tags/unbind | Scollega un identificatore dalla relativa Scheda |
| Imposta testo | POST /api/v1/tags/text | Rinomina o modifica la descrizione di un identificatore associato |
| Aggiorna | POST /api/v1/tags/update | Ciclo di vita: privacy, archiviazione/ripristino (valore e tipo sono immutabili) |
Identificare o verificare: l’identificazione risponde alla domanda «che cos’è?»: cerca tra le Schede visibili (nell’ambito definito da searchTeamIds) e restituisce l’eventuale corrispondenza. La verifica risponde alla domanda «è l’articolo che dichiara di essere?»: specifichi un threadId e gli identificatori candidati a esso associati e l’API conferma o nega. Usa la verifica per le decisioni di autenticazione e l’identificazione per la ricerca.
Due famiglie di payload
Sezione intitolata “Due famiglie di payload”Gli endpoint di scansione accettano multipart/form-data e la forma di data dipende dal tipo di identificatore:
tagType | data | Provenienza |
|---|---|---|
DUST | Un’immagine: una parte di file binaria o un URL dati base64 (data:image/jpeg;base64,…) | Un’acquisizione ottica DUST proveniente da uno scanner |
QR, BAR_CODE, DATA_MATRIX, NFC | Il contenuto decodificato della stringa (o l’ID NFC esadecimale) | Qualsiasi scanner di simboli |
TEXT | Il codice stampato leggibile da una persona, così come viene letto | Immissione da tastiera o registrazione di un’Etichetta |
Un’acquisizione DUST è una fotografia dell’identificatore, non un valore decodificato: il server estrae l’impronta. Le acquisizioni provengono dall’hardware di scansione DUST: consulta Integrare DUST Go per l’acquisizione da dispositivi mobili e React Scanner per un componente web pronto all’uso che gestisce tutte le modalità.
Nei corpi multipart, i campi strutturati (options, tags, searchTeamIds) vengono passati come stringhe JSON.
Identificatori testuali
Sezione intitolata “Identificatori testuali”TEXT è il codice leggibile da una persona stampato su un articolo o un’Etichetta, per esempio un numero di serie come AB00017. Non c’è alcun simbolo da decodificare, quindi il valore viene digitato (oppure proviene dal registro di registrazione di un’Etichetta) ed è memorizzato esattamente come inserito. Poiché il lettore è una persona, TEXT è l’unico tipo per il quale la piattaforma esegue la corrispondenza senza distinguere tra maiuscole e minuscole: identificando o verificando con ab00017 viene trovato un AB00017 associato. Per tutti gli altri tipi, la corrispondenza avviene byte per byte.
Come i valori QR, codice a barre, Data Matrix e NFC, un codice testuale è copiabile e non garantisce di per sé alcuna unicità: lo stesso codice può legittimamente comparire su più Schede o su ogni Etichetta di una Bobina. Un valore ripetuto non viene rifiutato; la Bobina segnala semplicemente le ripetizioni con un avviso.
Estrarre un’acquisizione DUST
Sezione intitolata “Estrarre un’acquisizione DUST”L’estrazione analizza un’acquisizione per ottenere un’impronta canonica e ne restituisce la qualità: è utile per controllare un’acquisizione prima della registrazione o per predisporre un’associazione:
curl -fsS "$APID_URL/api/v1/tags/extract" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "data=@scan.jpeg" \ -F 'options={"enrollmentSessionId":"3d5e…"}'La risposta è { id, qualityScore, annotatedImage?, forensics?, scan? }: id è l’ID di un’impronta che puoi associare successivamente senza caricare di nuovo l’immagine (vedi sotto). options contiene anche i metadati di acquisizione (dispositivo, ottica, geolocalizzazione) che la piattaforma memorizza con la scansione.
La ricevuta della scansione
Sezione intitolata “La ricevuta della scansione”Ogni operazione che invia un’immagine, ossia estrazione, associazione, identificazione, verifica e analisi delle alterazioni, restituisce un oggetto scan che indica ciò che è stato memorizzato:
{ "scanId": "…", "fingerprintId": "…", "dustId": "…" }scanIdè sempre presente dopo che l’immagine è stata memorizzata. È l’identità stabile dell’acquisizione e il valore da conservare se registri le operazioni di scansione nel tuo sistema.fingerprintIdè presente quando l’estrazione è riuscita (altrimenti ènull).dustIdè presente quando l’operazione ti ha restituito un DUST: l’identificatore creato da un’associazione, confermato da una verifica o risolto da un’identificazione. Ènullin caso di mancata corrispondenza, nessuna corrispondenza, estrazione o analisi delle alterazioni (in quest’ultimo caso l’identificatore è stato fornito da te, non risolto dall’immagine), nonché in un’identificazione che ha restituito più candidati (ogni candidato contiene il proprio identificatore).
Una mancata corrispondenza della verifica e l’assenza di corrispondenze nell’identificazione mantengono il proprio stato e codice di errore e includono la stessa ricevuta in detail.scan: la scansione è stata memorizzata anche se l’esito è stato negativo. Lo stesso vale per un’acquisizione rifiutata per motivi di qualità, perché contiene troppo pochi punti chiave utilizzabili o nessuno, indipendentemente dal codice di errore segnalato dall’operazione (/tags/extract risponde con SCAN_EXTRACTION_FAILURE; l’identificazione restituisce SCAN_LOW_KEYPOINTS / SCAN_NO_KEYPOINTS; la verifica risponde con il consueto IDENTIFIER_VERIFY_FAILED): l’immagine viene conservata e la relativa ricevuta presenta fingerprintId: null, perché non è stato possibile estrarne nulla di utilizzabile. Solo un’immagine che la piattaforma non è riuscita a decodificare affatto non viene memorizzata e non ha alcuna ricevuta.
Associare un identificatore a una Scheda
Sezione intitolata “Associare un identificatore a una Scheda”POST /api/v1/tags/bind accetta tre forme, distinte da tagType e dal payload:
curl -fsS "$APID_URL/api/v1/tags/bind" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "threadId=$THREAD_ID" \ -F "tagType=DUST" \ -F "tagDescription=Inbound receiving scan" \ -F "data=@scan.jpeg" \ -F 'options={"enrollmentSessionId":"3d5e…"}'# QR, BAR_CODE, DATA_MATRIX, NFC: the decoded contentscurl -fsS "$APID_URL/api/v1/tags/bind" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "threadId=$THREAD_ID" \ -F "tagType=QR" \ -F "data=https://example.com/item/SZ3J-11-ZJ17"# TEXT: the printed code as a person reads itcurl -fsS "$APID_URL/api/v1/tags/bind" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "threadId=$THREAD_ID" \ -F "tagType=TEXT" \ -F "data=AB00017"# Reuse a fingerprint from a prior /extract — no image re-uploadcurl -fsS "$APID_URL/api/v1/tags/bind" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "threadId=$THREAD_ID" \ -F "tagType=DUST" \ -F "fingerprintId=$FINGERPRINT_ID"options.enrollmentSessionId è facoltativo in un’associazione DUST. Fornisci un UUID generato dal client, usando lo stesso per tutta un’esecuzione, quando più acquisizioni sono correlate, per esempio quando una postazione di registrazione elabora un lotto o quando si acquisisce un articolo da più angolazioni; la piattaforma raggrupperà quindi tali scansioni nella stessa sessione. Omettilo completamente per un’associazione occasionale. Le associazioni da immagini DUST possono anche restituire l’acquisizione annotata impostando options.returnAnnotatedImage: true.
Associare un’Etichetta
Sezione intitolata “Associare un’Etichetta”Se l’identificatore scansionato fa parte di un’Etichetta di proprietà del Team della Scheda (vedi Etichette), l’associazione non crea un identificatore indipendente. Associa l’intera Etichetta: tutti gli identificatori membri attivi vengono collegati alla Scheda con un’unica operazione e la risposta contiene label (l’Etichetta, la relativa Bobina e la posizione) e boundTags (ogni membro associato), oltre al consueto tag, che rappresenta il membro scansionato. Passa activateLabel: true per rendere identificabili anche gli identificatori DUST dell’Etichetta nell’ambito dell’associazione; è facoltativo. Se un’Etichetta è già associata a un’altra Scheda, viene restituito IDENTIFIER_ALREADY_BOUND con detail.compositeTagId.
Identificare una Scheda da una scansione
Sezione intitolata “Identificare una Scheda da una scansione”curl -fsS "$APID_URL/api/v1/tags/identify" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "tagType=DUST" \ -F "data=@scan.jpeg" \ -F 'searchTeamIds=["'"$TEAM_ID"'"]'const result = await client.tags.identify({ tagType: "DUST", data: scanBlob, searchTeamIds: [teamId],});L’identificazione accetta anche payload di valore (tagType pari a QR/BAR_CODE/DATA_MATRIX/NFC con il data decodificato, oppure TEXT con il codice stampato, confrontato senza distinguere tra maiuscole e minuscole) o il solo ID dell’identificatore (tagType: "ANY" con tagId).
Cosa può restituire l’identificazione
Sezione intitolata “Cosa può restituire l’identificazione”Una corrispondenza restituisce 200 con l’identificatore corrispondente e la relativa Scheda. Un esito senza corrispondenze è uno stato di errore, non un 200 con un risultato vuoto: l’assenza definitiva di corrispondenze è 404 IDENTIFIER_NOT_FOUND, mentre una ricerca che non è stato possibile completare è 503 SCAN_SEARCH_INCOMPLETE, una situazione diversa che non deve essere mostrata a un operatore come «non trovato». Entrambe contengono la ricevuta della scansione in detail.scan.
La tabella canonica di tutti gli otto esiti — Scheda identificata, più candidati, Etichetta non associata, nessuna corrispondenza, ricerca incompleta, corrispondenza ambigua, acquisizione rifiutata, identificatore non associato — con lo stato, il codice e la risposta client corretta per ciascuno, si trova in Errori ed esiti delle scansioni → Esiti canonici dell’identificazione. Esegui la diramazione in base a code e leggi detail.outcome (no_match, search_incomplete, ambiguous, quality_reject) quando ti serve la distinzione più precisa.
Ogni identificatore restituito che appartiene a un’Etichetta contiene tag.label (la relativa Etichetta, Bobina e posizione). Quando la scansione corrisponde a un membro di un’Etichetta non associata nell’inventario del Team attivo, il risultato è { type: "label", label: { label, tags } }: non esiste ancora una Scheda, ma vengono restituiti l’Etichetta e i relativi identificatori membri, così che un client possa proporre di associarla (vedi Etichette).
Scegliere l’ambito di ricerca
Sezione intitolata “Scegliere l’ambito di ricerca”searchTeamIds è un array JSON di UUID di Team (una stringa JSON nei corpi multipart). Se lo ometti, l’identificazione cerca esattamente in un Team: quello specificato da Dust-Ctx-Team-Id, che per impostazione predefinita è il Team radice dell’organizzazione.
Gli ID non sono arbitrari. I Team della stessa organizzazione a cui appartieni rientrano sempre nell’ambito; il Team di un’organizzazione partner è raggiungibile solo tramite una Connessione attiva che consenta ai suoi dati di fluire verso di te. Tutto il resto viene rimosso silenziosamente dall’ambito anziché causare il fallimento della richiesta, quindi un ambito apparentemente ampio può produrre una ricerca ristretta. Individua gli ID validi invece di inserirli direttamente nel codice:
GET /api/v1/teams: i Team della tua organizzazione a cui appartengono le tue credenziali ({ teams: [{ teamId, orgId, name, … }], total }).GET /api/v1/teams/connected: i Team partner in cui puoi cercare, sotto forma di registri di Connessione che indicano i due Team collegati.
Verificare una scansione rispetto a una Scheda
Sezione intitolata “Verificare una scansione rispetto a una Scheda”La verifica è la primitiva di autenticazione: dati una nuova scansione, un threadId e i tags candidati già associati alla Scheda, ha esito positivo se un candidato corrisponde.
tags è obbligatorio ed è un array di oggetti, ciascuno nella forma { "tagId": "…", "tagType": "…" }, non un array di stringhe ID. In un corpo multipart viene inviato come stringa JSON:
curl -fsS "$APID_URL/api/v1/tags/verify" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "threadId=$THREAD_ID" \ -F "tagType=DUST" \ -F "data=@scan.jpeg" \ -F 'tags=[{"tagId":"'"$TAG_ID"'","tagType":"DUST"}]'const form = new FormData();form.set("threadId", threadId);form.set("tagType", "DUST");form.set("data", scanBlob);form.set("tags", JSON.stringify([{ tagId, tagType: "DUST" }]));Da dove provengono gli ID candidati
Sezione intitolata “Da dove provengono gli ID candidati”I valori tagId sono gli identificatori già associati alla Scheda che stai controllando. Leggili dalla Scheda: GET /api/v1/threads/{thread_id} li restituisce in thread.tags, ciascuno con il proprio tagId e tagType. Una verifica tipica recupera quindi la Scheda, filtra i relativi identificatori in base al tipo appena acquisito e li invia come elenco di candidati:
const record = await getThread(threadId); // GET /api/v1/threads/{thread_id}const candidates = (record.thread.tags ?? []) .filter((tag) => tag.tagType === "DUST") .map((tag) => ({ tagId: tag.tagId, tagType: tag.tagType }));L’invio di un identificatore non associato a quella Scheda fa fallire la verifica anziché produrre una corrispondenza con qualcos’altro.
Leggere il risultato
Sezione intitolata “Leggere il risultato”Il numero di candidati modifica la forma della risposta, e questo è l’errore di integrazione più comune:
Lunghezza di tags | Corrispondenza | Nessuna corrispondenza |
|---|---|---|
| Esattamente uno | 200 con { tag, scan? } | IDENTIFIER_VERIFY_FAILED (HTTP 500), ricevuta in detail.scan |
| Due o più | 200 con { success: true, verifiedTag, attemptedCount, failedCount, scan? } | 200 con { success: false, attemptedCount, failedCount, error, scan? } |
Pertanto, una verifica con più candidati senza corrispondenze è una chiamata HTTP riuscita che contiene success: false. Non considerare mai response.ok una prova di autenticità: leggi success ogni volta che invii più di un candidato. Consulta Errori ed esiti delle scansioni → Esiti della verifica.
Gestire gli identificatori associati
Sezione intitolata “Gestire gli identificatori associati”Questi sono normali endpoint JSON; tutti richiedono sia il tagId sia il threadId della Scheda a cui l’identificatore è associato:
POST /api/v1/tags/text: impostanamee/odescription.POST /api/v1/tags/update: impostaname,description,isPrivateearchivedAt(un timestamp ISO archivia l’identificatore;nulllo ripristina). Il valore e il tipo dell’identificatore sono immutabili: esegui invece una nuova associazione.POST /api/v1/tags/unbind: scollega l’identificatore dalla Scheda.
Analisi delle alterazioni
Sezione intitolata “Analisi delle alterazioni”Nello spazio /api/v1/tamper, un’Analisi delle alterazioni confronta una nuova scansione di un identificatore DUST con il riferimento acquisito al momento dell’associazione e registra ciò che è stato misurato. L’API restituisce solo misurazioni ed evidenze: nell’intera interfaccia non esiste alcun numero riepilogativo, fascia, soglia o campo di risultato formulato dalla piattaforma, mentre alignmentOutcome indica esclusivamente se è stato possibile confrontare le due scansioni (quando non è stato possibile, le misurazioni non sono confrontabili, il che non costituisce un’affermazione sull’identificatore).
| Operazione | Metodo e percorso |
|---|---|
| Esegui un’Analisi | POST /api/v1/tamper/analyses — codificato come modulo: threadId, tagId ed esattamente uno tra data e queryFingerprintId |
| Registra un’Osservazione | POST /api/v1/tamper/observations — { analysisId, result } |
| Elenca le Analisi di una Scheda | GET /api/v1/tamper/analyses?threadId=… (facoltativamente tagId, limit) |
| Recupera un’Analisi | GET /api/v1/tamper/analyses/{analysis_id} |
| Recupera una bitmap dei risultati | GET /api/v1/tamper/analyses/{analysis_id}/artifacts/{name} |
L’esecuzione di un’Analisi accetta un corpo multipart/form-data o application/x-www-form-urlencoded con threadId, tagId ed esattamente uno tra:
data: la scansione DUST stessa, come file o immagine codificata in base64. Il servizio la estrae per te.queryFingerprintId: l’ID di un’impronta già ottenuto tramitePOST /api/v1/tags/extract(vedi sopra), se hai eseguito l’estrazione separatamente.
L’invio di entrambi o di nessuno dei due viene rifiutato. In entrambi i casi, una normale acquisizione DUST è un input valido: non esiste un percorso di acquisizione separato per l’analisi delle alterazioni. Se la scansione inviata non può essere letta, la richiesta fallisce e non viene registrata alcuna Analisi.
Un’Osservazione sulle alterazioni è l’unica conclusione memorizzata dalla piattaforma ed è formulata da una persona: result è uno tra consistent, expected, inconsistent e unknown, non ha un valore predefinito ed è obbligatorio. expected registra la normale usura prevista per il caso d’uso e il substrato dell’identificatore. Le Osservazioni sono immutabili e attribuite; una nuova Osservazione non sostituisce mai una precedente e le letture restituiscono l’intera serie (observations, dalla più recente) anziché un singolo risultato corrente. Non ricavare un risultato dalle metriche e non ridurre la serie a un unico valore nella tua interfaccia utente.
Un’Analisi contiene metrics (un oggetto restituito senza modifiche contenente le frazioni di copertura e i conteggi dei marcatori dell’algoritmo), markerPoints facoltativi e artifactNames. Ogni insieme di coordinate dei marcatori è espresso nello spazio dei pixel della rispettiva scansione: componili nello stesso sistema di riferimento applicando metrics.transformation_matrix ai punti della query. Le bitmap dei risultati sono contenuti protetti: recuperale tramite l’endpoint degli artefatti, che autorizza nuovamente ogni richiesta e restituisce byte non memorizzabili nella cache.
Etichette
Sezione intitolata “Etichette”Un’Etichetta (nome nel protocollo: composite tag, spazio dei nomi /api/v1/composite-tags) è un’unica etichetta fisica che contiene uno o più identificatori di qualsiasi tipo; DUST non è obbligatorio. Le Etichette occupano una posizione su una Bobina (collection.kind = "reel", identificata dal relativo UUID; il suo name è il numero stampato della bobina o un titolo qualsiasi e non è mai univoco). Le Bobine possono essere archiviate in una Raccolta di etichette (kind = "reel_collection"), una cartella che non viene mai spedita. Il campo expectedIdentifiers di una Bobina indica quanti Identificatori di ciascun tipo contiene un’Etichetta completa al suo interno, nel formato [{ "tagType", "count" }] (per impostazione predefinita, un TEXT, un DUST e un QR; un count pari a 0 nell’input indica che quel tipo non è previsto). È un’indicazione per le postazioni di registrazione, non un vincolo, e il flag complete di un’Etichetta indica che contiene almeno il numero previsto di Identificatori attivi di ciascun tipo.
| Operazione | Metodo e percorso |
|---|---|
| Elenca / crea Raccolte di etichette | GET, POST /api/v1/composite-tags/collections; PATCH …/collections/{collection_id} |
| Elenca le Bobine | GET /api/v1/composite-tags/reels?collectionId=…&unfiled=…&transferred=any|only|hide&q=… |
| Crea una Bobina | POST /api/v1/composite-tags/reels — { name, description?, collectionId?, expectedIdentifiers? } |
| Recupera / aggiorna una Bobina | GET, PATCH /api/v1/composite-tags/reels/{reel_collection_id} (rinomina, modifica la composizione prevista; usa collectionId per spostarla e null per lasciarla senza raccolta) |
| Crea un’Etichetta | POST /api/v1/composite-tags/reels/{reel_collection_id}/labels (multipart) |
| Aggiungi / rimuovi un identificatore membro | POST /api/v1/composite-tags/{composite_tag_id}/identifiers (multipart); DELETE …/identifiers/{tag_id} |
| Elenca / recupera Etichette | GET /api/v1/composite-tags?reelCollectionId=…&bound=any|only|unbound&transferred=…&q=…; GET …/{composite_tag_id} |
| Risolvi un’Etichetta tramite il valore di un membro | POST /api/v1/composite-tags/resolve — { tagType, value, reelCollectionId? } (TEXT viene confrontato senza distinguere tra maiuscole e minuscole); la risposta contiene detail (prima corrispondenza) e candidates[] (tutte le corrispondenze, ordinate per posizione quando viene specificata una Bobina) |
| Sposta o taglia Etichette | POST /api/v1/composite-tags/move; controllo preliminare con POST /api/v1/composite-tags/move/preview |
| Associa / dissocia un’Etichetta | POST /api/v1/composite-tags/{composite_tag_id}/bind — { threadId, options?: { indexing: "default" } }; POST …/unbind |
| Associa in blocco un Intervallo della bobina | POST /api/v1/composite-tags/reels/{reel_collection_id}/bulk-bind — { fromPosition, toPosition, threadIds, activate?, dryRun? } |
| Archivia / ripristina un’Etichetta | POST …/{composite_tag_id}/archive, POST …/unarchive |
| Attiva | POST …/{composite_tag_id}/activate; POST /api/v1/composite-tags/reels/{reel_collection_id}/activate (in background) |
| Attiva identificatori DUST indipendenti | POST /api/v1/tags/activate — { tagIds[] } (fino a 200); un esito per identificatore, solo in avanti |
Creare una Bobina e registrare Etichette
Sezione intitolata “Creare una Bobina e registrare Etichette”curl -fsS "$APID_URL/api/v1/composite-tags/reels" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -H "Dust-Ctx-Team-Id: $DUST_TEAM_ID" \ -H "Content-Type: application/json" \ --data '{ "name": "0030", "expectedIdentifiers": [{ "tagType": "TEXT", "count": 1 }, { "tagType": "DUST", "count": 1 }, { "tagType": "QR", "count": 1 }] }'La risposta è { reel }, un riepilogo della Bobina con conteggi pari a zero. Conserva reel.collectionId, che identifica la Bobina. La creazione di una Bobina ne crea sempre una nuova: non avviene alcun riutilizzo in base al nome.
Ogni Etichetta richiede una richiesta multipart. Fornisci al massimo un’immagine DUST come data; tutti gli altri membri vengono forniti tramite identifiers, un array JSON di elementi { tagType, value }, oppure { tagType: "DUST", fingerprintId } per un ulteriore DUST già estratto con POST /api/v1/tags/extract. humanReadable e qrValue sono abbreviazioni rispettivamente per un membro TEXT e uno QR. Il valore predefinito di position è la successiva posizione libera sulla Bobina.
curl -fsS "$APID_URL/api/v1/composite-tags/reels/$REEL_COLLECTION_ID/labels" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -H "Dust-Ctx-Team-Id: $DUST_TEAM_ID" \ -F "position=1" \ -F "data=@scan.jpeg" \ -F 'identifiers=[{"tagType":"TEXT","value":"AB00001"},{"tagType":"QR","value":"https://v.example/ab00001"}]' \ -F 'options={"indexing":"none"}'Deve risultare almeno un identificatore. Una risposta con esito positivo contiene outcome: "created"; un nuovo tentativo con la stessa marcatura DUST nella stessa posizione viene riconciliato come outcome: "already_enrolled". Un DUST già presente su un’altra Etichetta o già associato restituisce 409 COMPOSITE_TAG_CONFLICT. I valori TEXT o QR ripetuti non vengono mai rifiutati: la Bobina li segnala invece in warnings, perché in alcune bobine un valore può essere legittimamente ripetuto.
options.indexing seleziona la modalità di indicizzazione DUST per l’immagine in data: default (identificabile), a meno che non venga richiesto none (solo verifica). Le postazioni di registrazione non presidiate in genere registrano in modalità solo verifica e attivano in seguito; l’attivazione indicizza ogni DUST ed esegue il controllo dei duplicati della piattaforma, quindi un’Etichetta il cui DUST duplica un DUST indicizzato viene segnalata e ignorata.
Il flusso equivalente con il client tipizzato è:
const created = await client.compositeTags.createReel({ name: "0030" });
const form = new FormData();form.set("position", "1");form.set("data", scanBlob);form.set("identifiers", JSON.stringify([{ tagType: "TEXT", value: "AB00001" }]));await client.compositeTags.createLabel(created.reel.collectionId, form);
const state = await client.compositeTags.getReel(created.reel.collectionId);await client.compositeTags.activateReel(created.reel.collectionId);Spostare e tagliare
Sezione intitolata “Spostare e tagliare”POST /api/v1/composite-tags/move accetta un source, un target e un expectedCount facoltativo.
Sono disponibili tre forme per l’origine:
{ compositeTagIds }: Etichette selezionate manualmente, spostate nell’ordine indicato.{ reelCollectionId, fromPosition, toPosition? }: un intervallo tipizzato di posizioni (un taglio); il valore predefinito ditoPositionè l’ultima posizione della Bobina.{ fromCompositeTagId, toCompositeTagId }: un taglio delimitato da scansioni, ossia la prima e l’ultima Etichetta dell’intervallo, in qualsiasi ordine. Il server legge le relative posizioni sotto lock; entrambe devono essere Etichette attive sulla stessa Bobina (altrimentidetail.reasoncontieneendpoints_on_different_reels,endpoint_archivedoendpoint_not_on_reel). Risolvi ogni Etichetta da un valore scansionato con/resolve(limitato alla Bobina, in modo che un codice stampato ripetuto produca piùcandidatesche il chiamante dovrà distinguere) oppure, per un DUST attivato, tramitePOST /api/v1/tags/identify.
Il target è { reelCollectionId } oppure { newReel: { name, description?, collectionId?, expectedIdentifiers? } } (una nuova Bobina eredita la composizione della Bobina di origine quando non ne viene specificata alcuna).
Ogni Etichetta attiva compresa in un intervallo viene spostata; le posizioni che contengono un’Etichetta archiviata o spedita, oppure nessuna Etichetta, sono spazi vuoti che rimangono sulla Bobina di origine. Le posizioni vengono mantenute quando sono tutte libere nella destinazione; in caso contrario, l’intero lotto viene aggiunto dopo l’ultima posizione della Bobina di destinazione, rispettando l’ordine di origine. La risposta elenca moved[] e, per un’origine basata su un intervallo o delimitata da scansioni, cut: { sourceReel, fromPosition, toPosition, count, boundCount, boundPositions, gaps[] }.
expectedCount rende il conteggio vincolante: quando è specificato, lo spostamento viene rifiutato con 400 INVALID_REQUEST e detail.reason: "count_mismatch" (expected, actual, fromPosition, toPosition), a meno che non vengano spostate esattamente quel numero di Etichette attive.
POST /api/v1/composite-tags/move/preview accetta lo stesso source, un target facoltativo e expectedCount, non modifica nulla e restituisce span, count, boundCount, la first e la last Etichetta del lotto, predictedOutcome (kept_positions / appended / null), countMatches e suggestedLast, cioè l’Etichetta più avanti lungo la Bobina che soddisferebbe expectedCount quando l’intervallo è troppo corto. È un suggerimento da scansionare per l’operatore e non viene mai applicato dal server. L’anteprima richiede il livello membro; lo spostamento richiede un amministratore del Team o dell’Organizzazione.
Associazione in blocco di un Intervallo della bobina
Sezione intitolata “Associazione in blocco di un Intervallo della bobina”POST /api/v1/composite-tags/reels/{reel_collection_id}/bulk-bind associa in ordine le Etichette nelle posizioni fromPosition..toPosition (incluse) ai threadIds: la k-esima posizione alla k-esima Scheda. L’operazione è tutto o niente e rigorosa: l’intervallo deve comprendere esattamente threadIds.length posizioni (toPosition è obbligatorio, non derivato, così il chiamante dichiara l’intervallo verificato sulla bobina), con al massimo 500 coppie per chiamata, e ogni posizione deve contenere un’Etichetta attiva e non associata. Il server non salta mai una posizione, perché così facendo sposterebbe silenziosamente tutti gli abbinamenti successivi.
Passa dryRun: true per eseguire il controllo preliminare senza effettuare l’associazione. La forma della risposta è identica in entrambi i casi:
outcome:"bound"dopo un’associazione effettiva,"preflight"per un’esecuzione di prova.rows[]: un elemento per abbinamento:index,position,compositeTagId(nullper una posizione vuota),labelName,textValue(il membroTEXTdell’Etichetta, ossia il codice stampato),threadId,threadName,threadDescription.blockers[]ewarnings[]:{ kind, index, position, compositeTagId?, threadId?, tagType?, existing? }.activation:"queued","not_requested","already_active"o"no_dust".reel: il riepilogo della Bobina con i conteggi aggiornati.
Tipi di blocco: position_empty, label_archived, label_transferred, label_bound, label_no_identifiers, identifier_bound_elsewhere, identifier_in_other_team_label, thread_not_owned, thread_unavailable, thread_in_transfer, thread_not_editable, thread_repeated. Tipi di avviso: label_incomplete (un’Etichetta con meno Identificatori di quanti ne preveda la Bobina) e thread_has_label (la Scheda contiene già un’Etichetta; existing[] le elenca). Gli avvisi non impediscono mai un’associazione.
Un commit con un qualsiasi blocco fallisce con 409 COMPOSITE_TAG_CONFLICT; detail contiene gli stessi rows, blockers e warnings di un’esecuzione di prova, così il client deve analizzare una sola forma. Un intervallo la cui lunghezza differisce da threadIds.length produce 400 INVALID_REQUEST.
Autorizzazione: appartenenza al Team per la Bobina e autorizzazione di modifica per ogni Scheda. Una Scheda che il chiamante non può modificare produce un blocco thread_not_editable per quella riga anziché il rifiuto dell’intera richiesta, e ogni Scheda deve essere di proprietà del Team della Bobina: una Scheda semplicemente condivisa con il Team produce thread_not_owned.
Con activate: true, l’associazione viene prima confermata, quindi un singolo processo in background attiva esattamente le marcature DUST delle Etichette associate; un’Etichetta la cui attivazione non riesce rimane associata e in modalità solo verifica. Controlla counts.identifiableCount della Bobina per monitorare l’avanzamento.
# Preflightcurl -fsS "$APID_URL/api/v1/composite-tags/reels/$REEL_COLLECTION_ID/bulk-bind" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -H "Dust-Ctx-Team-Id: $DUST_TEAM_ID" \ -H "Content-Type: application/json" \ --data '{ "fromPosition": 1, "toPosition": 3, "threadIds": ["'$THREAD_1'", "'$THREAD_2'", "'$THREAD_3'"], "dryRun": true }'
# Commit, activating the bound Labels afterwardscurl -fsS "$APID_URL/api/v1/composite-tags/reels/$REEL_COLLECTION_ID/bulk-bind" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -H "Dust-Ctx-Team-Id: $DUST_TEAM_ID" \ -H "Content-Type: application/json" \ --data '{ "fromPosition": 1, "toPosition": 3, "threadIds": ["'$THREAD_1'", "'$THREAD_2'", "'$THREAD_3'"], "activate": true }'Con il client tipizzato:
const preview = await client.compositeTags.bulkBind(reelCollectionId, { fromPosition: 1, toPosition: threadIds.length, threadIds, dryRun: true,});if (preview.blockers.length === 0) { await client.compositeTags.bulkBind(reelCollectionId, { fromPosition: 1, toPosition: threadIds.length, threadIds, activate: true, });}L’associazione lascia esattamente gli eventi prodotti da N associazioni singole: un evento bind per ciascun identificatore membro, ognuno contenente come destinazioni la Scheda, l’identificatore e l’Etichetta, tutti con lo stesso ID operazione.
Associare, dissociare e spedire
Sezione intitolata “Associare, dissociare e spedire”Un’Etichetta viene associata come un tutt’uno: POST …/{composite_tag_id}/bind collega alla Scheda l’Etichetta e ogni identificatore membro attivo; options.indexing: "default" la attiva anche. Lo stesso avviene quando chiami il normale POST /api/v1/tags/bind con un qualsiasi identificatore membro (vedi Associare un’Etichetta), come fanno gli scanner. L’associazione richiede l’autorizzazione di modifica sulla Scheda e che l’Etichetta sia di proprietà del Team; inoltre, la Scheda deve essere di proprietà dello stesso Team: un identificatore membro scansionato su una Scheda condivisa con te da un altro Team viene rifiutato (409 COMPOSITE_TAG_CONFLICT, reason: "label_owned_by_other_team") anziché essere associato come copia indipendente. POST …/unbind scollega l’Etichetta e tutti i relativi membri.
La proprietà del Team e dell’Organizzazione deriva esclusivamente dalle intestazioni di contesto, mentre il creatore deriva dal bearer token verificato. La lettura e l’attivazione delle Etichette richiedono l’appartenenza al Team. La creazione di Bobine, la registrazione, lo spostamento e l’archiviazione sono consentiti a un amministratore del Team o dell’Organizzazione autenticato oppure a un Service Account con ambito Organizzazione che sia membro del Team selezionato; un Service Account non può avvalersi dell’autorità di amministratore dell’Organizzazione.
Nelle Spedizioni, una Bobina è un articolo della distinta ({ kind: "reel", collectionId }) e viene spedita per intero, ma solo finché tutte le sue Etichette non sono associate. Un’Etichetta associata viene spedita con la relativa Scheda e non trascina mai la propria Bobina nella Spedizione. Le Bobine e le Etichette spedite rimangono leggibili sul lato mittente con transferredAt impostato; filtrale con transferred=only o transferred=hide.
Consulta Etichette e Bobine per il flusso di lavoro DICE.
Pagine correlate
Sezione intitolata “Pagine correlate”- Errori ed esiti delle scansioni: le tabelle canoniche degli esiti per l’identificazione e la verifica e come conservare la ricevuta di una scansione in caso di errore
- Integrare DUST Go: acquisizione di scansioni DUST su dispositivi mobili
- React Scanner: un componente di acquisizione pronto da copiare
- Guida all’API delle Schede: i registri a cui vengono associati gli identificatori
- Riferimento API: schemi completi, incluse le opzioni dei metadati di acquisizione