Dust Identity · AsyncAPI Specification

Dust Identity Events

Version

View Spec View on GitHub AuthenticationIdentitySupply ChainTraceabilityProvenanceAnti-CounterfeitingAsset TrackingAerospace and DefenseManufacturingSecurityAsyncAPIWebhooksEvents

AsyncAPI Specification

Raw ↑
generated: '2026-08-12'
method: searched
source: https://docs.dustid.io/use/activity/
also_from:
- https://docs.dustid.io/use/fabric/
- https://docs.dustid.io/use/disclosures/
- openapi/_original/dust-identity-apid-openapi-original.json
note: >-
  DUST has a rich, first-class event model and NO push contract for it. Every meaningful
  action on a Thread is recorded as an immutable event — that append-only history is the
  product, not a side effect — and the API exposes it through pollable REST collections
  with cursor pagination and action-type filters. What does not exist is any way to be
  told. There are no webhooks, no callbacks, no SSE or WebSocket stream, no queue, and no
  AsyncAPI document: the published OpenAPI 3.1 spec has no top-level `webhooks` object,
  the word "webhook" appears zero times in the complete 289KB documentation corpus, and
  so do "websocket", "server-sent" and "subscribe". The "notifications" surface is an
  in-app inbox that a client also polls, not a delivery mechanism.

  This file is therefore an EVENT CATALOG, not an AsyncAPI specification, and no AsyncAPI
  or Webhooks pointer is emitted in apis.yml — those pointers would assert DUST serves a
  push contract, and it does not. The catalog is recorded because the event types
  themselves are genuinely published and enumerated, and because an integrator needs to
  know that keeping an external system in sync with DUST means running a polling loop
  against GET /api/v1/events and checkpointing on the cursor.

push_contract:
  webhooks: false
  asyncapi: false
  websocket: false
  server_sent_events: false
  streaming: false
  callbacks_in_spec: false
  evidence: >-
    No `webhooks` object and no `callbacks` in the OpenAPI 3.1 document (147 paths,
    177 operations). Zero occurrences of webhook / websocket / server-sent / event stream /
    subscribe in https://docs.dustid.io/llms-full.txt (the complete docs site as one
    document, 289,078 bytes, fetched 2026-08-12).
  consequence: >-
    An agent or downstream system cannot be notified when a Thread changes, when an
    identifier is bound or a verification fails, or when a shipment arrives. It must poll.

delivery_model: poll
polling_surface:
- operationId: events.list
  method: GET
  path: /api/v1/events
  summary: List events
  role: the primary event log — a flat, Team-wide feed, one row per event
  pagination: cursor + pageSize (opaque cursor; a missing `next` means the last page)
  ordering: order=asc|desc
  filters:
  - name: actionFilter
    type: string or array of strings
    meaning: include only these action types
  - name: excludeActionFilter
    type: string
    meaning: exclude these action types
  - name: occurred
    type: string
    meaning: filter on when the event occurred — the field to checkpoint against
  - name: threadId
    meaning: scope to a single Thread (this is the Transaction History view)
  - name: orgId
    meaning: organization scope
  - name: teamId
    meaning: team scope
  - name: groupBy
    type: const "activity"
    meaning: collapse a multi-step operation (shipment, slice, CSV import, assembly install)
      into one grouped activity instead of its constituent rows
  - name: withTargets
    type: boolean
    meaning: hydrate the target resource on each event
  - name: withUser
    type: boolean
    meaning: hydrate the acting user on each event
  response_schema: EventListResponse
  recommended_checkpoint: the `occurred` timestamp, replayed with the cursor
- operationId: fabric.link_events
  method: GET
  path: /api/v1/fabric/links/{link_id}/events
  summary: Fabric Event Views for a Fabric Link
  role: events disclosed to you across a Fabric provenance link — the cross-organization
    view of upstream history
  response_schema: FabricLinkEventsResponse
  cursor_field: eventCursorOccurredAt
- operationId: transfer.preview_thread_events
  method: GET
  path: /api/v1/transfers/{transfer_id}/preview/threads/{source_thread_id}/events
  summary: Disclosed transaction history for an offered Thread
  role: the event history a receiving organization is allowed to see before accepting a
    shipment
  response_schema: TransferPreviewThreadEventsResponse

notification_inbox:
  note: >-
    Distinct from the event log. These are pending decisions addressed to an
    organization, held until acted on — an inbox a client polls, not a push channel.
  operations:
  - operationId: notifications.list
    method: GET
    path: /api/v1/notifications
    pagination: pageIndex + pageSize
    status_values: [accepted, canceled, pending, rejected]
  - operationId: fabric.list_notifications
    method: GET
    path: /api/v1/fabric/notifications
    summary: List Fabric notifications for the downstream owner
    status_values: [dismissed, pending, resolved]
  - operationId: fabric.preview_notification_decision
    method: POST
    path: /api/v1/fabric/notifications/{notification_id}/preview
    summary: Preview the effect of accepting before accepting
  - operationId: fabric.accept_notification
    method: POST
    path: /api/v1/fabric/notifications/{notification_id}/accept
  - operationId: fabric.reject_notification
    method: POST
    path: /api/v1/fabric/notifications/{notification_id}/reject
  - operationId: fabric.dismiss_notifications
    method: POST
    path: /api/v1/fabric/notifications/dismiss

event_types:
  source: https://docs.dustid.io/use/activity/
  note: >-
    The action types DUST enumerates in the Activity filter. These are the values
    actionFilter / excludeActionFilter select on. The spec types `action` as an open
    string (maxLength 64) rather than an enum, so this published list is the catalog —
    treat it as the documented set, not a closed one.
  count: 18
  types:
  - action: Created Thread
    domain: thread
  - action: Updated Thread
    domain: thread
  - action: Archived Thread
    domain: thread
  - action: Unarchived Thread
    domain: thread
  - action: Viewed Thread
    domain: thread
    note: hidden by default in the UI feed ("Hide viewed"); still returned by the API
  - action: Created Field
    domain: thread-data
  - action: Updated Field
    domain: thread-data
  - action: Bound
    domain: identifier
    meaning: a physical identifier was bound to a Thread
  - action: Bind Failed
    domain: identifier
  - action: Verified
    domain: identifier
    meaning: a scan was checked against the identifier already bound to a Thread
  - action: Verification Failed
    domain: identifier
  - action: Identified
    domain: identifier
    meaning: a scan resolved to a Thread
  - action: Identification Failed
    domain: identifier
  - action: Uploaded File
    domain: file
  - action: Document Verified
    domain: file
  - action: Created Folder
    domain: folder
  - action: Updated Folder
    domain: folder
  - action: Deleted Folder
    domain: folder

grouped_activities:
  note: >-
    groupBy=activity collapses the constituent events of one logical operation under a
    single header, with a roll-up of how many actions and people were involved.
  groups: [Shipment, Slice, Imported Thread, Assembly Position]

event_record_fields:
  source: EventListResponse / FabricDisclosedEvent in the OpenAPI, and the documented CSV export columns
  fields:
  - action
  - created
  - occurred-at time
  - event ID (UUID)
  - title
  - target type / target ID / target name
  - declaredActor (id, displayName, role, system)
  - user ID / user name / user email
  - organization and Team name
  - IP address
  - user agent
  - latitude / longitude
  - comment
  - summary of field changes
  export: >-
    DICE exports the same rows to CSV with full audit columns. There is no documented
    API operation for the CSV export; it is a web-app action.

integration_guidance:
  keeping_in_sync: >-
    Poll GET /api/v1/events with order=desc, page through with the cursor, and checkpoint
    on `occurred`. Cursors are documented as opaque — persist and replay them, never parse
    or construct them.
  scoping: >-
    Events are org- and team-scoped like every other endpoint; set Dust-Ctx-Org-Id (and
    Dust-Ctx-Team-Id when you want a non-root team). The same poll under a different team
    context legitimately returns a different feed.
  no_backoff_signal: >-
    DUST documents no rate limits and returns no 429 anywhere in the spec, so a polling
    loop has no published ceiling to design against and no Retry-After to obey. See
    rate-limits/dust-identity-rate-limits.yml.
  cost_of_polling: >-
    Because there is no push channel and no rate-limit contract, sync latency is entirely
    a function of how aggressively the integrator is willing to poll blind.

cross_links:
  conventions: conventions/dust-identity-conventions.yml
  rate_limits: rate-limits/dust-identity-rate-limits.yml
  data_model: data-model/dust-identity-data-model.yml
  conformance: conformance/dust-identity-conformance.yml