Authenticated agent API
The agent API is consumed by the agent dashboard running at https://agent.yumkiosk.com. Unlike the public kiosk API, it requires an authenticated agent session — you log in with email and password (or an OAuth provider in the future), get a Laravel session cookie, and every subsequent request includes that cookie. CSRF tokens are enforced for mutating requests per Laravel's default config.
Base URL: https://agent.yumkiosk.com/api.
Authentication
Every request must include the Laravel session cookie returned from POST /login. For mutating requests (POST, PUT, PATCH, DELETE), you must also include an X-XSRF-TOKEN header with the value from the XSRF-TOKEN cookie.
Unauthenticated requests return 401 Unauthorized. CSRF failures return 419 Page Expired (Laravel's convention).
GET /sessions/incoming
Returns the list of pending sessions this agent is eligible to accept. The dashboard polls this every 2 seconds as a fallback when the WebSocket is unavailable, but under normal operation the dashboard subscribes to a private channel and gets push events instead.
GET /sessions/incoming
Response:
{
"sessions": [
{
"id": "ses_8f2c1a",
"kiosk": {
"id": "kio_12",
"name": "Front counter",
"location": "Main St"
},
"business": { "id": "biz_3", "name": "Joe's Tacos" },
"created_at": "2026-04-10T14:22:00Z",
"waiting_seconds": 4
}
]
}
An empty list means there's nothing waiting — keep polling / listening.
POST /sessions/{id}/accept
Claim a pending session. Atomic: the first agent to call this wins, the others get 409 Conflict.
POST /sessions/ses_8f2c1a/accept
Response (success):
{
"session": {
"id": "ses_8f2c1a",
"status": "active",
"agora_channel": "ses_8f2c1a",
"kiosk": { "id": "kio_12", "name": "Front counter" },
"business": { "id": "biz_3", "name": "Joe's Tacos" }
}
}
Response (already accepted by someone else):
{
"error": {
"code": "SESSION_ALREADY_ACCEPTED",
"message": "This session was accepted by another agent."
}
}
POST /sessions/{id}/end
End an active session. Must be called by the agent who accepted it. The body specifies how the session ended:
POST /sessions/ses_8f2c1a/end
Content-Type: application/json
{
"reason": "completed",
"notes": "Two burgers, a large fries, paid with Visa."
}
Valid reason values: completed, customer_abandoned, technical_issue, refused_service.
Response:
{
"session": {
"id": "ses_8f2c1a",
"status": "completed",
"ended_at": "2026-04-10T14:26:30Z",
"duration_seconds": 270
}
}
GET /menu
Returns the full active catalog for the business the agent is currently working for. Fetched once per session and cached in-memory by the dashboard.
GET /menu
Response:
{
"categories": [
{
"id": "cat_burgers",
"name": "Burgers",
"sort_order": 10,
"menu_items": [
{
"id": "mi_burger",
"name": "Cheeseburger",
"description": "Angus beef with cheddar and house sauce",
"price_cents": 899,
"photo_url": "https://.../burger.jpg",
"modifier_groups": [
{
"id": "mg_doneness",
"name": "Doneness",
"required": true,
"min": 1,
"max": 1,
"options": [
{ "id": "mo_rare", "name": "Rare", "price_cents": 0 },
{ "id": "mo_medium", "name": "Medium", "price_cents": 0 },
{ "id": "mo_well", "name": "Well", "price_cents": 0 }
]
}
]
}
]
}
]
}
POST /orders
Add items to the active session's cart. Called every time the agent taps an item. The request body is the full cart — this API is PUT-semantics under a POST route because some proxies mangle PUT bodies.
POST /orders
Content-Type: application/json
{
"session_id": "ses_8f2c1a",
"lines": [
{
"menu_item_id": "mi_burger",
"quantity": 1,
"modifier_option_ids": ["mo_medium"],
"notes": "no onions"
},
{
"menu_item_id": "mi_fries",
"quantity": 1,
"modifier_option_ids": [],
"notes": ""
}
]
}
Response: the server computes totals and returns the full order object, identical to GET /sessions/{id}/order on the public API. It also broadcasts an OrderUpdated event to the kiosk over WebSocket so the kiosk cart updates instantly.
POST /agent/status
Change your own status (Available / Busy / Break / Offline). Also auto-updates last_seen_at.
POST /agent/status
Content-Type: application/json
{ "status": "available" }
Returns { "ok": true } on success. Invalid status values return 422 Unprocessable Entity.