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
| Field | Type | Required | Description |
|---|---|---|---|
| event_id | string (uuid) | Yes | UUID 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. |
| code | string | Yes | The scanned asset tag, external identifier (serial, GTIN) or lot label (LOT:<lot id>).Constraints: length 1 to 200 |
| action | "check-out" | "check-in" | "transfer" | Yes | check-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_id | string (uuid) | null | No | Identifier of the member who takes the item. |
| custodian_engagement_id | string (uuid) | null | No | Identifier of the external engagement that takes the item; never together with a member. |
| venue_id | string (uuid) | null | No | Identifier of the venue the item returns to; the unit's home venue by default. |
| project_id | string (uuid) | null | No | Identifier of the project the item is out for. |
| note | string | null | No | Hand-over note.Constraints: length 0 to 1000 |
| quantity | number | null | No | Lots 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
| Field | Type | Required | Description |
|---|---|---|---|
| outcome | "applied" | "duplicate" | Yes | applied for a new event; duplicate when the event id was already applied. |
| subject_kind | "unit" | "lot" | Yes | What the code named. |
| subject_id | string (uuid) | Yes | The asset unit or lot moved. |
| ledger_id | string (uuid) | Yes | The custody entry or lot movement, equal to the event id. |
| asset_state | "Proposed" | "Received" | "Available" | "Reserved" | "Deployed" | "In Maintenance" | "Damaged" | "Lost" | "Retired" | null | Yes | Units: the state after the move. |
| on_hand | number | null | Yes | Lots: 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}'