Operator guide
You run vending machines (kiosks) and want to plug their data into your own
dashboards, inventory tools, ERP, or restocking workflows. This guide walks
through what to use, when to use it, and what your credential can do —
organized by the jobs you actually do day to day. Fleet jobs are 0–5. Money
jobs — host venues, receiving stock, tax, the P&L — are 6–9. Console
onboarding for the money half is /playbook.
Base URL: https://api.kiosk-x.ai
Job 0 — Sign in and install a new machine
Sign in with your intelli-verse-x.ai account (the operator APK and console do this for you) and register the board's serial. Registration is the cloud half of physical installation: it provisions the serial so the kiosk app boots past the device gate, and the machine appears in your fleet with ten empty aisles.
# 1. Sign in → fleet-scoped bearer token (see authentication.md)
TOKEN=$(curl -s -X POST "$BASE/api/v1/auth/login" -H "Content-Type: application/json" \
-d '{"email":"you@intelli-verse-x.ai","password":"..."}' \
| python3 -c "import sys,json;print(json.load(sys.stdin)['data']['token'])")
# 2. Register the freshly installed board
curl -X POST "$BASE/api/v1/machines/register" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"machineNo":"866903013700099","name":"Gym Lobby","location":"24h Fitness, Queens"}'
# 3. Price + fill the aisles, then restock to max
curl -X POST "$BASE/api/v1/inventory/machines/866903013700099/restock" \
-H "Authorization: Bearer $TOKEN"
Power the kiosk on with the Kiosk X vending APK installed (see downloads) and it boots straight to the product grid.
Order doesn't matter: if the kiosk powers on before you register it, the cloud auto-provisions the board on first contact (fully stocked, in the unclaimed pool) so it still boots to a working grid — step 2 then claims the serial into your fleet, along with any vends it already took.
What you can use
Your API key determines what you can do. Check the scopes on your key:
| Scope | What it unlocks |
|---|---|
machines:read |
List your machines, see status/heartbeat/location |
machines:write |
Rename machines, update notes and location |
inventory:read |
See aisle-level stock, prices, fault flags |
inventory:write |
Change stock counts, prices, thresholds; trigger restocks |
orders:read |
Query sales history and revenue summaries |
orders:write |
Refund / fulfil orders (when your product role allows the action) |
commands:read |
Poll remote dispense command queue |
commands:write |
Enqueue / ack cloud-driven product drops |
machines:build |
Factory keys only — write build, QA, shipping, factory sign-off |
accounts:admin |
Create operator accounts (reseller/admin keys only) |
A standard operator key has all of these except accounts:admin and
machines:build. Calls beyond your scope return 403 Insufficient scope. You
only ever see your own machines and orders — other operators' resources
return 404. Roles, the operator picker, and who can see manufacturer
shipping: rbac.md.
Need a cloud reward drop (not a walk-up sale)? See hybrid-fulfillment.md.
Job 1 — Morning check: are my machines healthy?
curl "https://api.kiosk-x.ai/api/v1/machines" \
-H "X-API-Key: $KEY"
Look at each record's status (online / offline) and lastSeen (the last
heartbeat). A machine that hasn't been seen for more than ~10 minutes is
effectively down. Filter with ?status=offline to see only problem machines.
Job 2 — What needs restocking?
Pull aisle-level inventory for one machine:
curl "https://api.kiosk-x.ai/api/v1/inventory/machines/866903013700011" \
-H "X-API-Key: $KEY"
Each aisle reports currentStock, maxStock, and alertThreshold. An aisle
with currentStock <= alertThreshold is running low; faulted: true means the
dispensing mechanism reported an error and needs a visit.
For all machines in one call, use bulk inventory:
curl "https://api.kiosk-x.ai/api/v1/inventory" -H "X-API-Key: $KEY"
Job 3 — Record a refill visit
After physically refilling, set aisles back to max in one call
(requires inventory:write):
# Everything
curl -X POST ".../api/v1/inventory/machines/866903013700011/restock" \
-H "X-API-Key: $KEY"
# Only aisles 1, 2, 3
curl -X POST ".../api/v1/inventory/machines/866903013700011/restock" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"aisles": [1, 2, 3]}'
To correct a single aisle (partial counts, price changes, clearing a fault):
curl -X PUT ".../api/v1/inventory/machines/866903013700011/aisles/3" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"currentStock": 7, "sellingPrice": 6.49, "faulted": false}'
Only the fields you send are changed. Note: changes reach the physical machine on its next heartbeat (typically within a few minutes), not instantly.
Job 4 — How are sales going?
Quick revenue rollup across all your machines:
curl ".../api/v1/orders/summary" -H "X-API-Key: $KEY"
Detailed order history, filterable by machine and time window:
curl ".../api/v1/orders?machineNo=866903013700011&startTime=2026-08-01%2000:00:00&endTime=2026-08-10%2023:59:59" \
-H "X-API-Key: $KEY"
payStatus tells you the order state: shipped means paid and dispensed;
refunded means the customer got their money back (usually a dispense
failure — check the aisle's faulted flag).
Job 4b — Where did the card money go? (Nayax reconciliation)
Every card/wallet order carries a payment block naming the Nayax terminal
that took the tap and the Nayax merchant account it settled to — always
the machine owner's account, never anyone else's.
# Every cashless transaction with terminal, card brand/last4, settlement account
curl ".../api/v1/payments" -H "X-API-Key: $KEY"
# Totals grouped by Nayax account — match against your Nayax Core payout report
curl ".../api/v1/payments/summary" -H "X-API-Key: $KEY"
# Which reader is on which machine, and which account it feeds
curl ".../api/v1/payments/nayax/terminals" -H "X-API-Key: $KEY"
Full detail on the device wiring and settlement routing: Payments & Nayax.
Job 5 — Machine moved or renamed
curl -X PATCH ".../api/v1/machines/866903013700011" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"name": "Lobby Kiosk", "location": "Building B lobby", "lat": "40.7128", "lng": "-74.0060"}'
The money jobs
The jobs above are the fleet. Tax, host commission, cost of goods, and the P&L
are the other half of the product. The console's onboarding for that half is
/playbook; this section is the same
jobs over the API. Order matters: a tax rate and received stock affect
every later number, so put those on file before the host deal.
Job 6 — Connect a host venue and set the commission
If the cabinet has already been selling, name its serial on the venue. A
serial listed at create, or patched onto an existing venue with
kioskMachineNo / machineNos and a deploymentDate, accrues from that
date (or from first sale if you omit the date). A serial attached afterwards
by PATCH /api/v1/machines/{machineNo} with venueId is a move and accrues
only from the moment you attach it — everything sold before that earns the
host nothing, with no error, and a hostLink that reads linked / none as
if it were right.
# Accrues from first sale — new venue
curl -X POST ".../api/v1/crm/venues" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"name":"Riverside Gym","address":"12 Quay Street, Auckland",
"machineNos":["866903013700011"],"revShareBps":1500}'
# Same accrual rule — venue already exists. deploymentDate is the day it went in.
curl -X PATCH ".../api/v1/crm/venues/ven_4de41cc28efe" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"kioskMachineNo":"866903013700011","revShareBps":1500,
"deploymentDate":"2026-05-01"}'
revShareBps is basis points (1500 = 15%). Check it on GET /api/v1/pnl: a
host line showing vends: 0 against a cabinet that has sold is this ordering,
not a quiet month. Host statements: GET /api/v1/payouts.
Job 7 — Receive stock
Product cost is zero until you receive a purchase order. FIFO can only cost what it knows about — this is the usual reason a first P&L looks too good.
curl -X POST ".../api/v1/purchases" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"vendor":"Metro Cash","poRef":"PO-1042","orderedOn":"2026-08-01",
"lines":[{"sku":"DRK-SW","qty":24,"unitCostUsd":1.10}]}'
GET /api/v1/inventory/lots lists the layers. GET /api/v1/pnl returning
fifoCogsCents: 0 with sales on file is this job skipped.
Job 8 — Read the P&L
curl ".../api/v1/pnl" -H "X-API-Key: $KEY"
The payload carries an identity string:
gross − tax = net − FIFO − host − referrals − payroll − 2% fee − expenses =
operator net. Balance sheet: GET /api/v1/balance-sheet.
Job 9 — Sales tax
Put a fleet schedule on file with an effective date. A later schedule row
does not reprice stamped sales. Recording a cabinet's own jurisdiction rate
(PATCH /api/v1/machines/{machineNo} with salesTaxRate) does reprice
un-remitted history: chargedCents (the receipt) never moves; netCents and
tax do. A period already remitted or paid a host out on is refused, visibly,
at GET /api/v1/tax/restatements-blocked.
curl -X POST ".../api/v1/tax/schedules" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"bps":825,"effectiveAt":"2026-01-01"}'
The console /tax and /playbook describe the same three-part rule: the
receipt never moves, a later schedule row does not reprice stamped sales, and
a cabinet jurisdiction rate restates un-remitted history.
How a sale lands in the books
Operators do not POST sales. The cabinet does: Reyeah firmware via
POST /apk/createOrder (see architecture.md); ZHZN via a
physical card tap (field install §7).
A ZHZN §6 test vend moves product and does not open an order. Then read
GET /api/v1/orders and GET /api/v1/pnl.
Practical notes
- Rate limit: 1,000 requests/hour per key. Poll machines/inventory every
few minutes, not every second; a fleet of 20 machines checked every 5 minutes
uses ~480 requests/hour. On
429, wait for theRetry-Afterperiod. - Pagination: list endpoints take
page(1-based) andsize(max 100). - Every write is audited (who, what, when) — see Errors & rate limits.
- Prefer OAuth for server-to-server integrations: see Authentication.
Endpoint cheat sheet
| I want to… | Call |
|---|---|
| See all my machines | GET /api/v1/machines |
| Check one machine | GET /api/v1/machines/{machineNo} |
| Rename / relocate | PATCH /api/v1/machines/{machineNo} |
| Stock levels, all machines | GET /api/v1/inventory |
| Stock levels, one machine | GET /api/v1/inventory/machines/{machineNo} |
| Log a refill | POST /api/v1/inventory/machines/{machineNo}/restock |
| Fix one aisle / change price | PUT /api/v1/inventory/machines/{machineNo}/aisles/{aisleNo} |
| Revenue rollup | GET /api/v1/orders/summary |
| Order history | GET /api/v1/orders |
| One order's details | GET /api/v1/orders/{orderNumber} |
| Connect a host + commission | POST /api/v1/crm/venues (name machineNos if it has already sold) |
| Receive stock (FIFO) | POST /api/v1/purchases · GET /api/v1/inventory/lots |
| P&L | GET /api/v1/pnl |
| Host statements | GET /api/v1/payouts |
| Tax schedule | GET/POST /api/v1/tax/schedules |
| Blocked tax restatements | GET /api/v1/tax/restatements-blocked |
| Balance sheet | GET /api/v1/balance-sheet |