Identifiers API guide
An identifier connects a physical marking to a Thread: a DUST tag, QR code, barcode, Data Matrix symbol, or NFC chip. Once bound, a scan in the field resolves to the digital record. The API namespace is /api/v1/tags — legacy naming that survives in paths and schemas; these docs say identifier in prose.
Full request/response schemas: API reference.
Operations at a glance
Section titled “Operations at a glance”| Operation | Method & path | Semantics |
|---|---|---|
| Extract | POST /api/v1/tags/extract |
Parse a DUST capture into a canonical fingerprint, without binding |
| Bind | POST /api/v1/tags/bind |
Associate an identifier with a Thread |
| Identify | POST /api/v1/tags/identify |
Search: which Thread matches this scan? |
| Verify | POST /api/v1/tags/verify |
Compare a scan against a specific Thread’s identifiers |
| Unbind | POST /api/v1/tags/unbind |
Detach an identifier from its Thread |
| Set text | POST /api/v1/tags/text |
Rename / re-describe a bound identifier |
| Update | POST /api/v1/tags/update |
Lifecycle: privacy, archive/restore (value and type are immutable) |
Identify vs. verify: identify answers “what is this?” — it searches your visible Threads (optionally scoped by searchTeamIds) and returns the match, if any. Verify answers “is this the item it claims to be?” — you name a threadId and the candidate tag IDs, and the API confirms or denies. Use verify for authentication decisions; identify for lookup.
Two payload families
Section titled “Two payload families”Scan endpoints accept multipart/form-data, and the shape of data depends on the identifier type:
tagType |
data |
Where it comes from |
|---|---|---|
DUST |
An image — a binary file part or a base64 data URL (data:image/jpeg;base64,…) |
A DUST optical capture from a scanner |
QR, BAR_CODE, DATA_MATRIX, NFC |
The decoded string contents (or NFC hex ID) | Any symbol scanner |
A DUST capture is a photograph of the tag, not a decoded value — the server extracts the fingerprint. Captures come from DUST scanning hardware: see Integrate with DUST Go for mobile capture and the React Scanner for a drop-in web component that handles all modes.
In multipart bodies, structured fields (options, tags, searchTeamIds) are passed as JSON strings.
Extract a DUST capture
Section titled “Extract a DUST capture”Extract parses a capture into a canonical fingerprint and returns its quality — useful for checking a capture before enrolling, or for staging a bind:
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…"}'The response is { id, qualityScore, annotatedImage?, forensics? } — id is a fingerprint ID you can later bind without re-uploading the image (below). options also carries capture metadata (device, optics, geolocation) that the platform stores with the scan.
Bind an identifier to a Thread
Section titled “Bind an identifier to a Thread”POST /api/v1/tags/bind accepts three shapes, distinguished by tagType and 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…"}'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=QR" \ -F "data=https://example.com/item/SZ3J-11-ZJ17"# 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"DUST image binds group related captures with a client-generated options.enrollmentSessionId UUID, and can return the annotated capture (options.returnAnnotatedImage: true).
Identify a Thread from a scan
Section titled “Identify a Thread from a scan”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],});Identify also takes text payloads (tagType of QR/BAR_CODE/DATA_MATRIX/NFC with the decoded data) or a bare identifier ID (tagType: "ANY" with tagId). A hit returns the matched identifier and its Thread; a miss returns an unidentified result rather than an error.
Verify a scan against a Thread
Section titled “Verify a scan against a Thread”Verify is the authentication primitive: given a fresh scan, a threadId, and the candidate tags (identifier IDs bound to that Thread), it succeeds if any candidate matches.
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=["'"$TAG_ID"'"]'The response reports success, attemptedCount / failedCount, and on success the verifiedTag.
Manage bound identifiers
Section titled “Manage bound identifiers”These are plain JSON endpoints; all of them require both the tagId and the threadId the identifier is bound to:
POST /api/v1/tags/text— setnameand/ordescription.POST /api/v1/tags/update— setname,description,isPrivate, andarchivedAt(an ISO timestamp archives the identifier;nullrestores it). The identifier’s value and type are immutable — rebind instead.POST /api/v1/tags/unbind— detach the identifier from the Thread.
Tamper Analysis
Section titled “Tamper Analysis”Under /api/v1/tamper, a Tamper Analysis compares a fresh scan of a DUST identifier against the reference captured when it was bound and records what it measured. The API returns measurements and evidence only — there is no summary number, band, threshold, or platform-authored result field anywhere in the surface, and alignmentOutcome reports solely whether the two scans could be compared at all (when they could not, the measurements are not comparable, which is not a statement about the identifier).
| Operation | Method & path |
|---|---|
| Run an Analysis | POST /api/v1/tamper/analyses — form-encoded: threadId, tagId, and exactly one of data or queryFingerprintId |
| Record an Observation | POST /api/v1/tamper/observations — { analysisId, result } |
| List a Thread’s Analyses | GET /api/v1/tamper/analyses?threadId=… (optionally tagId, limit) |
| Get one Analysis | GET /api/v1/tamper/analyses/{analysis_id} |
| Fetch a result bitmap | GET /api/v1/tamper/analyses/{analysis_id}/artifacts/{name} |
Running an Analysis takes a multipart/form-data or application/x-www-form-urlencoded body with threadId, tagId, and exactly one of:
data— the DUST scan itself, as a file or base64-encoded image. The service extracts it for you.queryFingerprintId— a fingerprint ID you already hold fromPOST /api/v1/tags/extract(above), if you extracted separately.
Sending both, or neither, is rejected. Either way an ordinary DUST capture is valid input — there is no separate capture path for tamper analysis. If the submitted scan cannot be read, the request fails and no Analysis is recorded.
A Tamper Observation is the only conclusion the platform stores, and it is authored by a person: result is one of consistent, expected, inconsistent, or unknown, has no default, and is required. expected records normal wear and tear for the identifier’s use case and substrate. Observations are immutable and attributed; a new one never replaces an earlier one, and reads return the whole series (observations, newest first) rather than a single current result. Do not derive a result from the metrics or collapse the series to one value in your own UI.
An Analysis carries metrics (a pass-through object of the algorithm’s coverage fractions and marker counts), optional markerPoints, and artifactNames. Marker coordinate sets are each in their own scan’s pixel space — compose them in one frame by applying metrics.transformation_matrix to the query points. Result bitmaps are protected content: fetch them through the artifact endpoint, which re-authorizes every request and returns non-cacheable bytes.
Related pages
Section titled “Related pages”- Integrate with DUST Go — capturing DUST scans on mobile
- React Scanner — a copy-ready capture component
- Threads API guide — the records identifiers bind to
- API reference — full schemas, including capture metadata options
