Developers

Scanner API

Everything a mobile scanner app needs: sign in a scanner user, download the institute's item catalogue for offline lookup, and record stock in, stock out and transfers — immediately or when the device comes back online.

Base address

All endpoints live under /api/public/v1 on your GenoStock site address. Requests and responses are JSON. Send the access token from login as an Authorization: Bearer <token> header on every call after login.

Authorization: Bearer <access_token>
Content-Type: application/json

{base}/api/public/v1/…

Signing in

Scanner users are created by an administrator of the institute — they are separate from staff logins and can only use this API. Login returns a long-lived access token the app stores securely on the device.

  • Five failed attempts lock the account for 15 minutes
  • Administrators can revoke a scanner user at any time — the token stops working immediately
  • If the institute's subscription is not active, every call returns a clear error
  • Each scanner user counts as one seat on the subscription

Endpoints

POST
/auth/login

Authenticate a scanner user and receive an access token.

Request body

usernamestringrequiredScanner username, 3–40 characters
passwordstringrequiredScanner password
device_labelstringoptionalName of the device, shown to admins (max 80 characters)

Example response

{ "access_token": "…", "scanner_user": { "id": "…", "username": "…", "organisation": "…" } }
POST
/auth/logout

Invalidate the current access token.

Example response

{ "ok": true }
GET
/inventory/items

Download the institute's full item catalogue — barcodes, names, units and identifiers — so the app can recognise known barcodes while offline.

Example response

{ "items": [ { "id": "…", "barcode": "…", "name": "…", "unit": "…" } ] }
POST
/inventory/scan-in

Record stock arriving into a storeroom.

Request body

barcodestringrequiredScanned barcode (1–64 characters)
quantityintegerrequiredPositive whole number
batch_codestringoptionalSupplier batch or lot code (max 60 characters)
expiry_datestringoptionalYYYY-MM-DD
location_iduuidoptionalStoreroom; defaults to the main storeroom
notestringoptionalFree text, max 500 characters

Example response

{ "transaction_id": "…", "item": "…", "quantity": 10, "on_hand": 42 }
POST
/inventory/scan-out

Record stock leaving — consumption or patient use. The nearest-expiry batch is consumed first.

Request body

barcodestringrequiredScanned barcode
quantityintegerrequiredPositive whole number
batch_codestringoptionalTake from a specific batch
patient_referencestringoptionalPatient or case reference (max 120 characters)
location_iduuidoptionalStoreroom; defaults to the main storeroom
notestringoptionalFree text, max 500 characters

Example response

{ "transaction_id": "…", "item": "…", "quantity": 2, "on_hand": 40 }
POST
/inventory/transfer

Move stock between two storerooms of the same institute.

Request body

barcodestringrequiredScanned barcode
quantityintegerrequiredPositive whole number
from_location_iduuidrequiredSource storeroom
to_location_iduuidrequiredDestination storeroom
batch_codestringoptionalMove a specific batch
notestringoptionalFree text, max 500 characters

Example response

{ "transaction_id": "…", "item": "…", "quantity": 5, "from_on_hand": 15, "to_on_hand": 8 }
GET
/inventory/status

Current on-hand counts per item and storeroom — use it after an offline sync to confirm what the server recorded.

Example response

{ "status": [ { "item": "…", "location": "…", "on_hand": 42 } ] }

Errors

Errors are JSON with a machine-readable code and a human-readable message. Your app should branch on the code, not the message.

invalid_token401Token missing, expired or revoked — sign in again
invalid_credentials401Wrong username or password
account_locked423Too many failed attempts — wait 15 minutes
access_revoked403An administrator revoked this scanner user
subscription_inactive402The institute's subscription is not active
validation_error400Request body failed validation — see issues
invalid_quantity422Quantity must be a positive whole number
unknown_barcode404No catalogue item matches this barcode
invalid_location422Location missing or not part of this institute
insufficient_stock409Not enough stock on hand for that quantity
server_error500Something went wrong — safe to retry

Offline scanning and sync

The API is designed for store-rooms with poor connectivity. A well-behaved app works offline and syncs when a connection returns.

  • Cache the catalogue from GET /inventory/items and refresh it whenever the device is online
  • Queue scan-in, scan-out and transfer events locally with the time they happened
  • When back online, replay the queue in order — the server validates each event as if it had just happened
  • Call GET /inventory/status after a sync to reconcile counts

Managing scanner users

Scanner users are managed inside GenoStock, not through the API.

  • Administrators and inventory managers create scanner users under Scanners → Mobile scanner users
  • Each scanner user is tied to one institute and one subscription seat
  • Revoking a scanner user immediately invalidates its token, even on a device that is offline
  • Several devices can be registered against one institute account