Skip to main content

API: devices and inventory

General contract in How the API works.

Registration and removal belong to INSSA

POST /devices and DELETE /devices/:id require the reserved device_provisioning resource: a key gets 403. Everything else — read, edit, move, activate/deactivate and inventory — is available.

Querying

GET /devices
GET /devices/:id

List query: operationId, businessLine, isActive, type (spring, locker, liquid, coffee, return), search (name, serial or city), page, pageSize (max 1000).

A device response (trimmed):

{
"id": "665f…d1",
"serial": "ICS595DDE99B",
"name": "Vending Corferias 1",
"businessLine": "vending",
"currency": "COP",
"accountId": "665f…c6",
"operationId": "665f…c7",
"specs": {
"type": "spring",
"brand": "INSSA SNACKS",
"model": "IKA 5 COMBI",
"paymentMethods": { "cashless": true, "cash": false, "card": true }
},
"location": { "country": "Colombia", "city": "Bogotá", "address": "Corferias", "coordinates": null },
"controller": { "serial": "ICS595DDE99B", "status": "online" },
"planogramKind": "physical",
"isActive": true,
"lastTransmission": "2026-08-11T13:58:22.000Z"
}

Editing and moving

PATCH /devices/:id { "name": "…", "location": { … }, "specs": { … } }
PATCH /devices/:id/scope { "operationId": "665f…c8" }
PATCH /devices/:id/deactivate
PATCH /devices/:id/activate

PATCH /devices/:id accepts name, location, specs and peripherals; brand and peripherals can only be changed by a global operator (403 for everyone else).

PATCH /devices/:id/scope moves the device to another operation. A key can only move it within its account; moving across accounts needs client or global level.

Activate and deactivate answer 204.

Inventory (planogram)

PUT /devices/:id/planogram
PATCH /devices/:id/slots/:selection
POST /devices/:id/slots/:selection/load
DELETE /devices/:id/slots/:selection

They require device_inventory:update, which the key has.

Replacing the whole planogram

PUT /devices/:id/planogram — send the final structure: rows and slots. It replaces whatever was there, so anything you omit is deleted.

{
"kind": "physical",
"rows": [{ "rowId": "R1", "name": "Bandeja 1", "capacity": 12 }],
"slots": [
{
"selection": "11",
"rowId": "R1",
"productId": "665f…b1",
"maxQty": 20,
"minQty": 3,
"currentQty": 12,
"price": 3000
}
]
}

Rules: every slot references a declared row, the selection is unique (uppercase and digits, max 8), and return modules take no planogram (400 devices.planogram_not_applicable).

Adjusting one slot

PATCH /devices/:id/slots/:selection — optional fields, null to clear:

FieldTypeNotes
productIdstring | nullnull empties the slot
maxQty / minQty / currentQtyinteger | null≥ 0
priceinteger | nullminor units. In cashless the device reports the charge

Restocking

POST /devices/:id/slots/:selection/load{ "productId": "665f…b1", "qty": 20, "price": 3000 }. This is the natural endpoint for the restocking process: sets product and quantity in one go.

DELETE /devices/:id/slots/:selection empties the slot.

They all return 200 with the updated device (or 204 on the DELETE).

Own errors: 404 devices.not_found, 404 devices.slot_not_found, 409 devices.slot_conflict, 400 devices.product_mismatch, 400 devices.invalid_planogram_shape, 403 devices.not_visible_to_scope.