YumKiosk YumKiosk Docs
Website Agent login Owner panel
API Reference

Authenticated agent API

Endpoints used by the agent dashboard after login.

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.