Przewodnik po API identyfikatorów
Identyfikator łączy fizyczne oznakowanie z rekordem: może to być identyfikator DUST, kod QR, kod kreskowy, symbol Data Matrix, układ NFC lub wydrukowany kod tekstowy. Po powiązaniu skan wykonany w terenie prowadzi do rekordu cyfrowego. Przestrzeń nazw API to /api/v1/tags — starsza nazwa, która przetrwała w ścieżkach i schematach; w tekście tej dokumentacji używamy słowa identyfikator.
Pełne schematy żądań i odpowiedzi: dokumentacja referencyjna API. Wszystkie wyniki, jakie może zwrócić każda operacja — także te, które przychodzą jako błędy HTTP — zebrano w jednej tabeli w artykule Błędy i wyniki skanowania.
Przegląd operacji
Dział zatytułowany „Przegląd operacji”| Operacja | Metoda i ścieżka | Znaczenie |
|---|---|---|
| Wyodrębnienie | POST /api/v1/tags/extract | Przetwarza ujęcie DUST na kanoniczny odcisk cyfrowy, bez wiązania |
| Powiązanie | POST /api/v1/tags/bind | Wiąże identyfikator z rekordem |
| Identyfikacja | POST /api/v1/tags/identify | Wyszukiwanie: który rekord pasuje do tego skanu? |
| Weryfikacja | POST /api/v1/tags/verify | Porównuje skan z identyfikatorami konkretnego rekordu |
| Odłączenie | POST /api/v1/tags/unbind | Odłącza identyfikator od jego rekordu |
| Ustawienie tekstu | POST /api/v1/tags/text | Zmienia nazwę lub opis powiązanego identyfikatora |
| Aktualizacja | POST /api/v1/tags/update | Cykl życia: prywatność, archiwizacja i przywracanie (wartość i typ są niezmienne) |
Identyfikacja a weryfikacja: identyfikacja odpowiada na pytanie „co to jest?” — przeszukuje widoczne dla ciebie rekordy (w zakresie określonym przez searchTeamIds) i zwraca dopasowanie, jeśli istnieje. Weryfikacja odpowiada na pytanie „czy to jest przedmiot, za który się podaje?” — wskazujesz threadId i powiązane z nim identyfikatory kandydujące, a API potwierdza lub zaprzecza. Weryfikacji używaj przy decyzjach o autentyczności, identyfikacji — do wyszukiwania.
Dwie rodziny ładunków
Dział zatytułowany „Dwie rodziny ładunków”Punkty końcowe skanowania przyjmują multipart/form-data, a postać pola data zależy od typu identyfikatora:
tagType | data | Źródło |
|---|---|---|
DUST | Obraz — binarna część pliku lub adres URL danych base64 (data:image/jpeg;base64,…) | Optyczne ujęcie DUST ze skanera |
QR, BAR_CODE, DATA_MATRIX, NFC | Zdekodowana zawartość w postaci tekstu (lub szesnastkowe ID NFC) | Dowolny skaner symboli |
TEXT | Wydrukowany kod czytelny dla człowieka, w takiej postaci, w jakiej odczytuje go osoba | Wpisanie z klawiatury lub rejestracja etykiety |
Ujęcie DUST to zdjęcie identyfikatora, a nie zdekodowana wartość — odcisk cyfrowy wyodrębnia serwer. Ujęcia pochodzą ze sprzętu do skanowania DUST: zobacz Integracja z DUST Go, aby dowiedzieć się o przechwytywaniu na urządzeniach mobilnych, oraz React Scanner — gotowy komponent internetowy obsługujący wszystkie tryby.
W treściach multipart pola strukturalne (options, tags, searchTeamIds) przekazuje się jako ciągi JSON.
Identyfikatory tekstowe
Dział zatytułowany „Identyfikatory tekstowe”TEXT to czytelny dla człowieka kod wydrukowany na przedmiocie lub etykiecie — numer seryjny, taki jak AB00017. Nie ma tu symbolu do zdekodowania, więc wartość jest wpisywana (lub pochodzi z zapisu rejestracji etykiety) i przechowywana dokładnie w takiej postaci, w jakiej ją wprowadzono. Ponieważ odczytuje ją człowiek, TEXT jest jedynym typem, który platforma dopasowuje bez rozróżniania wielkości liter: identyfikacja lub weryfikacja z wartością ab00017 znajduje powiązany identyfikator AB00017. Wszystkie pozostałe typy są dopasowywane bajt po bajcie.
Podobnie jak wartości QR, kodów kreskowych, Data Matrix i NFC kod tekstowy można skopiować i sam w sobie nie zapewnia unikatowości — ten sam kod może zgodnie z przeznaczeniem występować na kilku rekordach albo na każdej etykiecie rolki. Powtórzona wartość nie jest nigdy odrzucana; rolka po prostu zgłasza powtórzenia jako ostrzeżenie.
Wyodrębnianie ujęcia DUST
Dział zatytułowany „Wyodrębnianie ujęcia DUST”Wyodrębnianie przetwarza ujęcie na kanoniczny odcisk cyfrowy i zwraca jego jakość — przydaje się do sprawdzenia ujęcia przed rejestracją albo do przygotowania powiązania:
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…"}'Odpowiedź ma postać { id, qualityScore, annotatedImage?, forensics?, scan? } — id to ID odcisku cyfrowego, który możesz później powiązać bez ponownego przesyłania obrazu (patrz niżej). options zawiera też metadane ujęcia (urządzenie, optyka, geolokalizacja), które platforma przechowuje razem ze skanem.
Raport skanu
Dział zatytułowany „Raport skanu”Każda operacja przesyłająca obraz — wyodrębnianie, powiązanie, identyfikacja, weryfikacja i analiza manipulacji — zwraca obiekt scan wskazujący, co zostało zapisane:
{ "scanId": "…", "fingerprintId": "…", "dustId": "…" }scanIdjest zawsze obecne, gdy obraz został zapisany. To stała tożsamość ujęcia i wartość, którą warto zachować, jeśli zapisujesz operacje skanowania po swojej stronie.fingerprintIdjest obecne, gdy wyodrębnianie się powiodło (w przeciwnym razienull).dustIdjest obecne, gdy operacja zwróciła ci DUST: identyfikator utworzony przez powiązanie, potwierdzony przez weryfikację lub wskazany przez identyfikację. Ma wartośćnullw przypadku niezgodności, braku dopasowania, wyodrębniania, analizy manipulacji (identyfikator podajesz tam sam, a nie jest on wynikiem rozpoznania obrazu) oraz identyfikacji, która zwróciła kilku kandydatów (każdy kandydat zawiera własny identyfikator).
Niezgodność przy weryfikacji i brak dopasowania przy identyfikacji zachowują dotychczasowy status i kod błędu, a ten sam raport skanu przekazują w detail.scan — skan został zapisany, mimo że wynik był negatywny. Tak samo jest z ujęciem odrzuconym z powodu jakości — za mało lub brak użytecznych punktów kluczowych — niezależnie od kodu błędu, jaki zgłasza dla niego operacja (/tags/extract odpowiada SCAN_EXTRACTION_FAILURE; identyfikacja zwraca SCAN_LOW_KEYPOINTS / SCAN_NO_KEYPOINTS; weryfikacja odpowiada swoim zwykłym IDENTIFIER_VERIFY_FAILED): obraz zostaje zachowany, a jego raport skanu ma fingerprintId: null, ponieważ nie wyodrębniono z niego niczego użytecznego. Tylko obraz, którego platforma w ogóle nie mogła zdekodować, nie jest zapisywany i nie ma raportu skanu.
Powiązanie identyfikatora z rekordem
Dział zatytułowany „Powiązanie identyfikatora z rekordem”POST /api/v1/tags/bind przyjmuje trzy postacie, rozróżniane przez tagType i ładunek:
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 jest opcjonalne przy powiązaniu DUST. Podaj UUID wygenerowany po stronie klienta — ten sam przez cały przebieg — gdy kilka ujęć stanowi całość, na przykład gdy stanowisko rejestracji przetwarza partię albo gdy jeden przedmiot jest uchwycony pod kilkoma kątami; platforma grupuje wtedy te skany w ramach tej sesji. W przypadku jednorazowego powiązania pomiń to pole całkowicie. Powiązania z obrazem DUST mogą też zwrócić ujęcie z adnotacjami, jeśli ustawisz options.returnAnnotatedImage: true.
Powiązanie etykiety
Dział zatytułowany „Powiązanie etykiety”Jeśli zeskanowany identyfikator należy do etykiety, której właścicielem jest zespół rekordu (patrz Etykiety), powiązanie nie tworzy samodzielnego identyfikatora. Wiąże całą etykietę: każdy aktywny identyfikator członkowski zostaje powiązany z rekordem w jednej operacji, a odpowiedź zawiera label (etykietę, jej rolkę i pozycję) oraz boundTags (wszystkie powiązane identyfikatory członkowskie) obok zwykłego pola tag, które wskazuje zeskanowany identyfikator członkowski. Przekaż activateLabel: true, aby w ramach powiązania uczynić również identyfikatory DUST etykiety identyfikowalnymi; jest to opcjonalne. Etykieta powiązana już z innym rekordem zwraca IDENTIFIER_ALREADY_BOUND z detail.compositeTagId.
Identyfikacja rekordu na podstawie skanu
Dział zatytułowany „Identyfikacja rekordu na podstawie skanu”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],});Identyfikacja przyjmuje też ładunki z wartością (tagType równy QR/BAR_CODE/DATA_MATRIX/NFC ze zdekodowanym data albo TEXT z wydrukowanym kodem, dopasowywanym bez rozróżniania wielkości liter) lub samo ID identyfikatora (tagType: "ANY" z tagId).
Co może zwrócić identyfikacja
Dział zatytułowany „Co może zwrócić identyfikacja”Trafienie zwraca 200 z dopasowanym identyfikatorem i jego rekordem. Brak trafienia to status błędu, a nie 200 z pustym wynikiem: ostateczny brak dopasowania to 404 IDENTIFIER_NOT_FOUND, a wyszukiwanie, którego nie udało się ukończyć, to 503 SCAN_SEARCH_INCOMPLETE — inna sytuacja, której nie wolno pokazywać operatorowi jako „nie znaleziono”. Oba przypadki zawierają raport skanu w detail.scan.
Kanoniczna tabela wszystkich ośmiu wyników — zidentyfikowany rekord, kilku kandydatów, niepowiązana etykieta, brak dopasowania, niekompletne wyszukiwanie, niejednoznaczne dopasowanie, odrzucone ujęcie, niepowiązany identyfikator — wraz ze statusem, kodem i właściwą reakcją klienta dla każdego z nich znajduje się w artykule Błędy i wyniki skanowania → Kanoniczne wyniki identyfikacji. Rozgałęziaj logikę według code, a gdy potrzebujesz dokładniejszego rozróżnienia, odczytaj detail.outcome (no_match, search_incomplete, ambiguous, quality_reject).
Każdy zwrócony identyfikator należący do etykiety zawiera tag.label (swoją etykietę, rolkę i pozycję). Gdy skan pasuje do identyfikatora członkowskiego niepowiązanej etykiety z zasobów aktywnego zespołu, wynikiem jest { type: "label", label: { label, tags } }: nie ma jeszcze rekordu, ale jest etykieta i jej identyfikatory członkowskie, więc klient może zaproponować jej powiązanie (patrz Etykiety).
Wybór zakresu wyszukiwania
Dział zatytułowany „Wybór zakresu wyszukiwania”searchTeamIds to tablica JSON z UUID zespołów (w treściach multipart — ciąg JSON). Jeśli go pominiesz, identyfikacja przeszuka dokładnie jeden zespół: ten wskazany przez Dust-Ctx-Team-Id, który domyślnie wskazuje zespół główny organizacji.
Wartości ID nie mogą być dowolne. Zespoły z tej samej organizacji, do których należysz, są zawsze w zakresie; zespół organizacji partnerskiej jest osiągalny tylko przez aktywne połączenie, które pozwala na przepływ jego danych do ciebie. Wszystkie inne są po cichu usuwane z zakresu, zamiast powodować niepowodzenie żądania, więc zakres, który wygląda na szeroki, może w praktyce przeszukiwać wąsko. Zamiast wpisywać prawidłowe wartości ID na sztywno, ustal je:
GET /api/v1/teams— zespoły w twojej organizacji, do których należą twoje poświadczenia ({ teams: [{ teamId, orgId, name, … }], total }).GET /api/v1/teams/connected— zespoły partnerskie, które możesz przeszukiwać, w postaci rekordów połączeń wskazujących dwa połączone zespoły.
Weryfikacja skanu względem rekordu
Dział zatytułowany „Weryfikacja skanu względem rekordu”Weryfikacja to podstawowa operacja uwierzytelniania: mając świeży skan, threadId i kandydujące identyfikatory tags już powiązane z tym rekordem, kończy się powodzeniem, jeśli pasuje którykolwiek kandydat.
tags jest wymagane i jest tablicą obiektów — każdy w postaci { "tagId": "…", "tagType": "…" } — a nie tablicą ciągów z ID. W treści multipart przesyła się je jako ciąg 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" }]));Skąd pochodzą ID kandydatów
Dział zatytułowany „Skąd pochodzą ID kandydatów”Wartości tagId to identyfikatory już powiązane ze sprawdzanym rekordem. Odczytaj je z rekordu: GET /api/v1/threads/{thread_id} zwraca je w thread.tags, każdy z jego tagId i tagType. Typowa weryfikacja pobiera więc rekord, filtruje jego identyfikatory do typu, który właśnie przechwycono, i wysyła je jako listę kandydatów:
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 }));Wysłanie identyfikatora, który nie jest powiązany z tym rekordem, powoduje niepowodzenie weryfikacji, a nie dopasowanie czegoś innego.
Odczytywanie wyniku
Dział zatytułowany „Odczytywanie wyniku”Liczba kandydatów zmienia postać odpowiedzi — to najczęstszy błąd integracji w tym miejscu:
Długość tags | Dopasowanie | Brak dopasowania |
|---|---|---|
| Dokładnie jeden | 200 z { tag, scan? } | IDENTIFIER_VERIFY_FAILED (HTTP 500), raport skanu w detail.scan |
| Dwa lub więcej | 200 z { success: true, verifiedTag, attemptedCount, failedCount, scan? } | 200 z { success: false, attemptedCount, failedCount, error, scan? } |
Nieudana weryfikacja z wieloma kandydatami to więc udane wywołanie HTTP zawierające success: false. Nigdy nie traktuj response.ok jako dowodu autentyczności — odczytuj success za każdym razem, gdy wysyłasz więcej niż jednego kandydata. Zobacz Błędy i wyniki skanowania → Wyniki weryfikacji.
Zarządzanie powiązanymi identyfikatorami
Dział zatytułowany „Zarządzanie powiązanymi identyfikatorami”To zwykłe punkty końcowe JSON; wszystkie wymagają zarówno tagId, jak i threadId rekordu, z którym powiązany jest identyfikator:
POST /api/v1/tags/text— ustawianamei/lubdescription.POST /api/v1/tags/update— ustawianame,description,isPrivateiarchivedAt(znacznik czasu ISO archiwizuje identyfikator;nullgo przywraca). Wartość i typ identyfikatora są niezmienne — zamiast tego powiąż go ponownie.POST /api/v1/tags/unbind— odłącza identyfikator od rekordu.
Analiza manipulacji
Dział zatytułowany „Analiza manipulacji”W ramach /api/v1/tamper analiza manipulacji porównuje świeży skan identyfikatora DUST z ujęciem referencyjnym wykonanym przy powiązaniu i zapisuje wyniki pomiarów. API zwraca wyłącznie wyniki pomiarów i dowody — w całym interfejsie nie ma żadnej liczby podsumowującej, przedziału, progu ani pola wyniku ustalanego przez platformę, a alignmentOutcome informuje wyłącznie o tym, czy oba skany w ogóle dało się porównać (jeśli nie, wyniki pomiarów są nieporównywalne, co nie jest żadnym stwierdzeniem na temat identyfikatora).
| Operacja | Metoda i ścieżka |
|---|---|
| Uruchomienie analizy | POST /api/v1/tamper/analyses — w postaci formularza: threadId, tagId i dokładnie jedno z pól data lub queryFingerprintId |
| Zapisanie obserwacji | POST /api/v1/tamper/observations — { analysisId, result } |
| Lista analiz rekordu | GET /api/v1/tamper/analyses?threadId=… (opcjonalnie tagId, limit) |
| Pobranie jednej analizy | GET /api/v1/tamper/analyses/{analysis_id} |
| Pobranie mapy bitowej wyniku | GET /api/v1/tamper/analyses/{analysis_id}/artifacts/{name} |
Uruchomienie analizy wymaga treści multipart/form-data lub application/x-www-form-urlencoded z polami threadId, tagId oraz dokładnie jednym z pól:
data— sam skan DUST jako plik lub obraz zakodowany w base64. Usługa wyodrębnia go za ciebie.queryFingerprintId— ID odcisku cyfrowego uzyskane wcześniej zPOST /api/v1/tags/extract(patrz wyżej), jeśli wyodrębnianie wykonano osobno.
Wysłanie obu pól albo żadnego zostaje odrzucone. W obu przypadkach zwykłe ujęcie DUST jest prawidłowymi danymi wejściowymi — dla analizy manipulacji nie ma osobnej ścieżki przechwytywania. Jeśli przesłanego skanu nie da się odczytać, żądanie kończy się niepowodzeniem i analiza nie zostaje zapisana.
Obserwacja dotycząca manipulacji to jedyny wniosek, jaki przechowuje platforma, a jej autorem jest człowiek: result przyjmuje jedną z wartości consistent, expected, inconsistent lub unknown, nie ma wartości domyślnej i jest wymagane. expected oznacza normalne zużycie, typowe dla przeznaczenia i podłoża identyfikatora. Obserwacje są niezmienne i przypisane do autora; nowa nigdy nie zastępuje wcześniejszej, a odczyty zwracają całą serię (observations, od najnowszej), a nie jeden bieżący wynik. We własnym interfejsie nie ustalaj wyniku na podstawie metryk ani nie sprowadzaj serii do jednej wartości.
Analiza zawiera metrics (obiekt przekazywany bez zmian, z ułamkami pokrycia i liczbami znaczników wyznaczonymi przez algorytm), opcjonalne markerPoints oraz artifactNames. Każdy zestaw współrzędnych znaczników jest wyrażony w przestrzeni pikseli własnego skanu — aby umieścić je w jednym układzie, zastosuj metrics.transformation_matrix do punktów zapytania. Mapy bitowe wyników są treścią chronioną: pobieraj je przez punkt końcowy artefaktów, który ponownie autoryzuje każde żądanie i zwraca bajty nienadające się do buforowania.
Etykiety
Dział zatytułowany „Etykiety”Etykieta (nazwa w protokole: composite tag, przestrzeń nazw /api/v1/composite-tags) to jedna fizyczna etykieta zawierająca jeden lub więcej identyfikatorów dowolnego typu; DUST nie jest wymagany. Etykiety zajmują pozycje na rolce (collection.kind = "reel", identyfikowanej przez UUID; jej name to wydrukowany numer rolki lub dowolny tytuł i nigdy nie jest unikatowe). Rolki można umieszczać w kolekcji etykiet (kind = "reel_collection"), czyli folderze, który nigdy nie jest wysyłany. Pole expectedIdentifiers rolki określa, ile identyfikatorów każdego typu ma kompletna etykieta na tej rolce, w postaci [{ "tagType", "count" }] (domyślnie po jednym TEXT, DUST i QR; wartość count równa 0 na wejściu oznacza, że dany typ nie jest oczekiwany). Jest to wskazówka dla stanowisk rejestracji, a nie ograniczenie, a pole complete etykiety oznacza, że ma ona co najmniej tyle aktywnych identyfikatorów każdego oczekiwanego typu.
| Operacja | Metoda i ścieżka |
|---|---|
| Lista / tworzenie kolekcji etykiet | GET, POST /api/v1/composite-tags/collections; PATCH …/collections/{collection_id} |
| Lista rolek | GET /api/v1/composite-tags/reels?collectionId=…&unfiled=…&transferred=any|only|hide&q=… |
| Tworzenie rolki | POST /api/v1/composite-tags/reels — { name, description?, collectionId?, expectedIdentifiers? } |
| Pobieranie / aktualizacja rolki | GET, PATCH /api/v1/composite-tags/reels/{reel_collection_id} (zmiana nazwy, oczekiwany skład, collectionId do przeniesienia; null usuwa ją z kolekcji) |
| Tworzenie etykiety | POST /api/v1/composite-tags/reels/{reel_collection_id}/labels (multipart) |
| Dodawanie / usuwanie identyfikatora członkowskiego | POST /api/v1/composite-tags/{composite_tag_id}/identifiers (multipart); DELETE …/identifiers/{tag_id} |
| Lista / pobieranie etykiet | GET /api/v1/composite-tags?reelCollectionId=…&bound=any|only|unbound&transferred=…&q=…; GET …/{composite_tag_id} |
| Rozpoznawanie etykiety po wartości identyfikatora członkowskiego | POST /api/v1/composite-tags/resolve — { tagType, value, reelCollectionId? } (TEXT jest dopasowywany bez rozróżniania wielkości liter); odpowiedź zawiera detail (pierwsze dopasowanie) i candidates[] (wszystkie dopasowania, w kolejności pozycji, gdy podano rolkę) |
| Przenoszenie lub odcinanie etykiet | POST /api/v1/composite-tags/move; kontrola wstępna przez POST /api/v1/composite-tags/move/preview |
| Powiązanie / odłączenie etykiety | POST /api/v1/composite-tags/{composite_tag_id}/bind — { threadId, options?: { indexing: "default" } }; POST …/unbind |
| Powiązanie zbiorcze zakresu rolki | POST /api/v1/composite-tags/reels/{reel_collection_id}/bulk-bind — { fromPosition, toPosition, threadIds, activate?, dryRun? } |
| Archiwizacja / przywracanie etykiety | POST …/{composite_tag_id}/archive, POST …/unarchive |
| Aktywacja | POST …/{composite_tag_id}/activate; POST /api/v1/composite-tags/reels/{reel_collection_id}/activate (w tle) |
| Aktywacja samodzielnych identyfikatorów DUST | POST /api/v1/tags/activate — { tagIds[] } (do 200); jeden wynik na identyfikator, bez możliwości cofnięcia |
Tworzenie rolki i rejestracja etykiet
Dział zatytułowany „Tworzenie rolki i rejestracja etykiet”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 }] }'Odpowiedź to { reel }, podsumowanie rolki z zerowymi licznikami. Zachowaj reel.collectionId; identyfikuje ono rolkę. Utworzenie rolki zawsze tworzy nową rolkę: nie ma ponownego użycia po nazwie.
Każda etykieta to jedno żądanie multipart. Jako data podaj co najwyżej jeden obraz DUST; każdy inny identyfikator członkowski przekazuje się przez identifiers — tablicę JSON z wpisami { tagType, value } lub { tagType: "DUST", fingerprintId } dla kolejnego DUST już wyodrębnionego przez POST /api/v1/tags/extract. humanReadable i qrValue to skróty dla identyfikatorów członkowskich typu TEXT i QR. position domyślnie przyjmuje następną wolną pozycję na rolce.
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"}'W wyniku musi powstać co najmniej jeden identyfikator. Udana odpowiedź ma outcome: "created"; ponowienie z tym samym oznakowaniem DUST na tej samej pozycji jest uzgadniane jako outcome: "already_enrolled". DUST, który jest już na innej etykiecie lub jest już powiązany, zwraca 409 COMPOSITE_TAG_CONFLICT. Powtórzone wartości TEXT lub QR nigdy nie są odrzucane: zamiast tego rolka zgłasza je w warnings, ponieważ na niektórych rolkach powtarzanie wartości jest zamierzone.
options.indexing wybiera tryb indeksowania DUST dla obrazu w data: default (identyfikowalny), chyba że zażądasz none (tylko weryfikacja). Bezobsługowe stanowiska rejestracji zwykle rejestrują w trybie tylko weryfikacji i aktywują później; aktywacja indeksuje każdy DUST i uruchamia sprawdzanie duplikatów przez platformę, więc etykieta, której DUST powiela już zaindeksowany, zostaje zgłoszona i pominięta.
Ten sam przepływ w kliencie typowanym:
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);Przenoszenie i odcinanie
Dział zatytułowany „Przenoszenie i odcinanie”POST /api/v1/composite-tags/move przyjmuje source, target i opcjonalne expectedCount.
Trzy postacie źródła:
{ compositeTagIds }— ręcznie wybrane etykiety, przenoszone w podanej kolejności.{ reelCollectionId, fromPosition, toPosition? }— wpisany zakres pozycji (odcięcie);toPositiondomyślnie przyjmuje ostatnią pozycję rolki.{ fromCompositeTagId, toCompositeTagId }— odcięcie wyznaczone skanami: pierwsza i ostatnia etykieta odcinka, w dowolnej kolejności. Serwer odczytuje ich pozycje pod blokadą; obie muszą być aktywnymi etykietami na tej samej rolce (w przeciwnym razieendpoints_on_different_reels,endpoint_archivedlubendpoint_not_on_reelwdetail.reason). Każdą etykietę rozpoznasz na podstawie zeskanowanej wartości przez/resolve(w zakresie rolki, tak aby powtórzony wydrukowany kod pojawił się jako kilka elementówcandidatesdo rozstrzygnięcia przez wywołującego) albo — w przypadku aktywowanego DUST — przezPOST /api/v1/tags/identify.
target ma postać { reelCollectionId } lub { newReel: { name, description?, collectionId?, expectedIdentifiers? } } (nowa rolka dziedziczy skład rolki źródłowej, jeśli go nie podano).
Przenoszona jest każda aktywna etykieta w obrębie odcinka; pozycje z zarchiwizowaną lub wysłaną etykietą albo bez etykiety to luki, które pozostają na rolce źródłowej. Pozycje są zachowywane, gdy wszystkie są wolne na rolce docelowej; w przeciwnym razie cała partia jest dopisywana za ostatnią pozycją rolki docelowej w kolejności źródłowej. Odpowiedź zawiera moved[] oraz — dla źródła w postaci zakresu lub odcięcia wyznaczonego skanami — cut: { sourceReel, fromPosition, toPosition, count, boundCount, boundPositions, gaps[] }.
expectedCount sprawia, że liczba staje się warunkiem: jeśli ją podano, przeniesienie zostaje odrzucone z kodem 400 INVALID_REQUEST i detail.reason: "count_mismatch" (expected, actual, fromPosition, toPosition), chyba że przeniesionych zostałoby dokładnie tyle aktywnych etykiet.
POST /api/v1/composite-tags/move/preview przyjmuje to samo source, opcjonalne target i expectedCount, niczego nie zmienia i zwraca span, count, boundCount, etykiety first i last partii, predictedOutcome (kept_positions / appended / null), countMatches oraz suggestedLast — etykietę położoną dalej na rolce, przy której zostałby spełniony warunek expectedCount, gdy odcinek jest za krótki. To tylko sugestia, którą operator może zeskanować; serwer nigdy jej nie stosuje. Podgląd jest dostępny na poziomie członka; przeniesienie wymaga administratora zespołu lub organizacji.
Powiązanie zbiorcze zakresu rolki
Dział zatytułowany „Powiązanie zbiorcze zakresu rolki”POST /api/v1/composite-tags/reels/{reel_collection_id}/bulk-bind wiąże etykiety na pozycjach fromPosition..toPosition (włącznie) z threadIds po kolei: k-tą pozycję z k-tym rekordem. Operacja jest typu „wszystko albo nic” i ścisła: zakres musi obejmować dokładnie threadIds.length pozycji (toPosition jest wymagane, a nie wyliczane, aby wywołujący wskazał zakres sprawdzony na rolce), w jednym wywołaniu może być najwyżej 500 par, a każda pozycja musi zawierać aktywną, niepowiązaną etykietę. Serwer nigdy nie pomija pozycji, ponieważ pominięcie po cichu przesunęłoby każde kolejne przyporządkowanie.
Przekaż dryRun: true, aby wykonać kontrolę wstępną bez wiązania. Postać odpowiedzi jest w obu przypadkach taka sama:
outcome—"bound"po rzeczywistym powiązaniu,"preflight"dla przebiegu próbnego.rows[]— jeden wiersz na każde przyporządkowanie:index,position,compositeTagId(null dla pustej pozycji),labelName,textValue(identyfikator członkowskiTEXTetykiety, czyli wydrukowany kod),threadId,threadName,threadDescription.blockers[]iwarnings[]—{ kind, index, position, compositeTagId?, threadId?, tagType?, existing? }.activation—"queued","not_requested","already_active"lub"no_dust".reel— podsumowanie rolki ze zaktualizowanymi licznikami.
Rodzaje blokad: 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. Rodzaje ostrzeżeń: label_incomplete (etykieta z mniejszą liczbą identyfikatorów, niż oczekuje rolka) i thread_has_label (rekord ma już etykietę; wskazuje je existing[]). Ostrzeżenia nigdy nie zatrzymują powiązania.
Zatwierdzenie z jakąkolwiek blokadą kończy się niepowodzeniem z kodem 409 COMPOSITE_TAG_CONFLICT; detail zawiera te same rows, blockers i warnings co przebieg próbny, więc klient zawsze analizuje tylko jedną postać. Zakres, którego długość różni się od threadIds.length, daje 400 INVALID_REQUEST.
Uprawnienia: członkostwo w zespole rolki oraz uprawnienie do edycji każdego rekordu. Rekord, którego wywołujący nie może edytować, jest blokadą thread_not_editable dla danego wiersza, a nie powodem odrzucenia całego żądania, a każdy rekord musi należeć do zespołu rolki — rekord jedynie udostępniony zespołowi daje thread_not_owned.
Przy activate: true powiązanie zostaje najpierw zatwierdzone, a następnie jedno zadanie w tle aktywuje oznakowania DUST dokładnie tych powiązanych etykiet; etykieta, której aktywacja nie powiedzie się, pozostaje powiązana w trybie tylko weryfikacji. Postęp sprawdzaj, odpytując counts.identifiableCount rolki.
# 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 }'Z klientem typowanym:
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, });}Powiązanie pozostawia dokładnie te same zdarzenia co N pojedynczych powiązań: jedno zdarzenie bind na każdy identyfikator członkowski, z rekordem, identyfikatorem i etykietą jako obiektami docelowymi, wszystkie ze wspólnym ID operacji.
Powiązanie, odłączenie i wysyłka
Dział zatytułowany „Powiązanie, odłączenie i wysyłka”Etykieta jest wiązana w całości: POST …/{composite_tag_id}/bind wiąże etykietę i każdy aktywny identyfikator członkowski z rekordem; options.indexing: "default" dodatkowo ją aktywuje. To samo dzieje się, gdy wywołasz zwykłe POST /api/v1/tags/bind z dowolnym identyfikatorem członkowskim (patrz Powiązanie etykiety) — tak właśnie działają skanery. Powiązanie wymaga uprawnienia do edycji rekordu, etykieta musi należeć do zespołu, a rekord — do tego samego zespołu: identyfikator członkowski zeskanowany na rekordzie, który udostępnił ci inny zespół, zostaje odrzucony (409 COMPOSITE_TAG_CONFLICT, reason: "label_owned_by_other_team"), a nie powiązany jako samodzielna kopia. POST …/unbind odłącza etykietę i wszystkie jej identyfikatory członkowskie.
Własność zespołu i organizacji wynika wyłącznie z nagłówków kontekstu, a twórca — ze zweryfikowanego tokenu Bearer. Odczyt i aktywacja etykiet wymagają członkostwa w zespole. Tworzenie rolek, rejestracja, przenoszenie i archiwizacja są dostępne dla zalogowanego administratora zespołu lub organizacji albo dla konta usługi o zakresie organizacji, które jest członkiem wybranego zespołu; konto usługi nie może przejąć uprawnień administratora organizacji.
W przesyłkach rolka jest pozycją manifestu ({ kind: "reel", collectionId }) i jest wysyłana w całości, ale tylko wtedy, gdy każda etykieta na niej jest niepowiązana. Powiązana etykieta jest wysyłana razem ze swoim rekordem i nigdy nie dołącza swojej rolki do przesyłki. Wysłane rolki i etykiety pozostają czytelne po stronie nadawcy z ustawionym transferredAt; możesz je filtrować za pomocą transferred=only lub transferred=hide.
Opis przepływu pracy w DICE znajdziesz w artykule Etykiety i rolki.
Powiązane strony
Dział zatytułowany „Powiązane strony”- Błędy i wyniki skanowania — kanoniczne tabele wyników identyfikacji i weryfikacji oraz sposób zachowania raportu skanu w razie niepowodzenia
- Integracja z DUST Go — przechwytywanie skanów DUST na urządzeniach mobilnych
- React Scanner — gotowy do skopiowania komponent do przechwytywania
- Przewodnik po API rekordów — rekordy, z którymi wiążą się identyfikatory
- Dokumentacja referencyjna API — pełne schematy, w tym opcje metadanych ujęcia