Skip to content

Apply a scan event

Assets module

POST/asset-units/scansassetUnits.applyScan

Applies one scanned custody move in one transaction (app.apply_asset_scan): resolves the code to a unit or lot, writes the custody entry or lot movement under the device's event id, and moves the unit's state. Replaying an event id returns `duplicate` and changes nothing. A unit someone else moved meanwhile is refused (422, asset_scan_state_conflict); a code no item carries is refused with NO_ANSWER. Requires `Idempotency-Key`; a replay returns the original response. A rule that refuses the request returns 422 with `refusal` and `reason`.

  • Requires the capability assets.custody.write.
  • OAuth scopes: assets.
  • Send an Idempotency-Key header. A replay with the same key returns the original response.
  • Error statuses: 400, 401, 409, 422, 429. Errors are RFC 9457 problem details.

Request body: AssetScanEvent

assetUnits.applyScan: AssetScanEvent
FieldTypeRequiredDescription
event_idstring (uuid)YesUUID the device minted when the scan happened and keeps in its offline queue. It becomes the custody entry or lot movement id, so replaying the event at any later time changes nothing.
codestringYesThe scanned asset tag, external identifier (serial, GTIN) or lot label (LOT:<lot id>).Constraints: length 1 to 200
action"check-out" | "check-in" | "transfer"Yescheck-out hands the item to one custodian (the unit becomes Deployed); check-in returns it to a venue (the unit becomes Available); transfer passes a deployed unit to another custodian.
custodian_membership_idstring (uuid) | nullNoIdentifier of the member who takes the item.
custodian_engagement_idstring (uuid) | nullNoIdentifier of the external engagement that takes the item; never together with a member.
venue_idstring (uuid) | nullNoIdentifier of the venue the item returns to; the unit's home venue by default.
project_idstring (uuid) | nullNoIdentifier of the project the item is out for.
notestring | nullNoHand-over note.Constraints: length 0 to 1000
quantitynumber | nullNoLots only: how many move.
{
  "event_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e70",
  "code": "NWL-RAD-014",
  "action": "check-out",
  "custodian_membership_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "custodian_engagement_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "venue_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "project_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "note": "Stage left radio.",
  "quantity": 12
}

Response 200: AssetScanResult

assetUnits.applyScan: AssetScanResult
FieldTypeRequiredDescription
outcome"applied" | "duplicate"Yesapplied for a new event; duplicate when the event id was already applied.
subject_kind"unit" | "lot"YesWhat the code named.
subject_idstring (uuid)YesThe asset unit or lot moved.
ledger_idstring (uuid)YesThe custody entry or lot movement, equal to the event id.
asset_state"Proposed" | "Received" | "Available" | "Reserved" | "Deployed" | "In Maintenance" | "Damaged" | "Lost" | "Retired" | nullYesUnits: the state after the move.
on_handnumber | nullYesLots: the quantity on hand after the move.
{
  "outcome": "applied",
  "subject_kind": "unit",
  "subject_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "ledger_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "asset_state": "Available",
  "on_hand": 72
}

Code samples

curl -X POST "$XOS_BASE_URL/asset-units/scans" \
  -H "Authorization: Bearer $XOS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"event_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e70","code":"NWL-RAD-014","action":"check-out","custodian_membership_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","custodian_engagement_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","venue_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","project_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","note":"Stage left radio.","quantity":12}'
const { data } = await xos.assetUnits.applyScan({
    "event_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e70",
    "code": "NWL-RAD-014",
    "action": "check-out",
    "custodian_membership_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
    "custodian_engagement_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
    "venue_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
    "project_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
    "note": "Stage left radio.",
    "quantity": 12
  });
response = xos.asset_units.apply_scan({"event_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e70", "code": "NWL-RAD-014", "action": "check-out", "custodian_membership_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f", "custodian_engagement_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f", "venue_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f", "project_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f", "note": "Stage left radio.", "quantity": 12})
xos asset-units apply-scan --data '{"event_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e70","code":"NWL-RAD-014","action":"check-out","custodian_membership_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","custodian_engagement_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","venue_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","project_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","note":"Stage left radio.","quantity":12}'