{"openapi":"3.1.0","info":{"title":"Kiosk-X Partner API","description":"\n## Overview\nThe **Kiosk-X Partner API** is the Intelliverse X vending cloud for smart-kiosk\noperators: register machines, monitor aisle-level inventory, query orders,\nreconcile Nayax payments, roll out APK updates, and manage stock — one\nself-contained stack, backed by deterministic mock data in the sandbox.\n\n**Hybrid fulfillment (KioskX extension):** keep walk-up sales on-machine\n(`channel=walkup`), and use cloud `api_drop` commands when you need a remote\nproduct drop. Machine agents poll pending commands, drive the motor, then ack.\n\nUse it to build and test integrations without touching production vending data.\n\n## Authentication\nFour interchangeable methods:\n\n| Method | How |\n|--------|-----|\n| Intelliverse sign-in | `POST /api/v1/auth/login` (email + password) or `POST /api/v1/auth/login/social` (Google/Apple ID token, existing operators only) → MFA ticket → `Authorization: Bearer <token>` |\n| API key | `X-API-Key` header (partner keys) |\n| Sandbox OAuth | `POST /oauth/token` (client_credentials) → `Authorization: Bearer <token>` |\n| Intelliverse Cognito | Bearer JWT from the Intelliverse user pool |\n\nScopes: `machines:read`, `machines:write`, `inventory:read`, `inventory:write`,\n`orders:read`, `commands:read`, `commands:write`, `accounts:admin`. A key lacking\nthe required scope receives `403 Insufficient scope`.\n\n## Response format\n```json\n{\"code\": 200, \"message\": \"success\", \"data\": { ... }}\n```\nErrors use the same envelope with a non-200 `code` and `data: null`.\n\n## Rate limiting\nEach credential has an hourly request limit. Exceeding it returns\n`429 Rate limit exceeded` with `Retry-After: 3600`.\n\nFull guides: [GitHub docs](https://github.com/intelli-verse-x/kiosk-x/tree/main/docs)\n· Hybrid: [hybrid-fulfillment.md](https://github.com/intelli-verse-x/kiosk-x/blob/main/docs/hybrid-fulfillment.md)\n","version":"v1"},"servers":[{"url":"https://api.kiosk-x.ai","description":"Kiosk-X sandbox"}],"paths":{"/health":{"get":{"tags":["Sandbox"],"summary":"Health check","description":"Mirrors VTM's health response. db/redis are emulated in-memory.","operationId":"health_health_get","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"db":"ok","redis":"ok"}}}}}}}},"/sandbox/readiness":{"get":{"tags":["Sandbox"],"summary":"Live endpoint readiness self-test","description":"Exercises every endpoint in-process and reports pass/fail with latency.\n\nBrowsers get an HTML dashboard; API clients get JSON (or force with\n?format=json / ?format=html).","operationId":"readiness_sandbox_readiness_get","parameters":[{"name":"format","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Format"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"service":"kiosk-x","version":"v1","uptimeSeconds":4523,"mode":"sandbox (mock data)","overall":"pass","dataset":{"operators":2,"machines":4,"aisles":40,"orders":380},"auth":{"apiKeys":3,"oauthClients":3,"cognitoIssuer":"https://cognito-idp.us-east-1.amazonaws.com/us-east-1_M5qxN8b74"},"selfTest":[{"check":"GET /api/v1/machines","target":"GET /api/v1/machines","status":200,"expected":200,"latencyMs":2.1,"pass":true}]}}}}}}}},"/sandbox/audit":{"get":{"tags":["Sandbox"],"summary":"Audit log","description":"Every write operation recorded (key, user, action, resource, timestamp).","operationId":"audit_log_sandbox_audit_get","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":[{"keyId":"key_admin","userId":"kiosk-x-admin@intelli-verse-x.ai","action":"inventory.restock","resource":"machine/866903013700011","timestamp":"2026-08-10T12:00:00.000+0000"}]}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/sandbox/reset":{"post":{"tags":["Sandbox"],"summary":"Reset sandbox data","description":"Restore the deterministic seed dataset.\n\nMoney semantics: the sandbox fleet (machines, aisles, orders) re-seeds,\nbut persisted money-adjacent records are REHYDRATED back on top — a\nsandbox reset is not a financial-history eraser. Pass ``wipeMoney=true``\nto explicitly drop the persisted ledger too (also clears the in-memory\nprize entries and funding outbox so memory matches the emptied mirror).","operationId":"reset_sandbox_reset_post","parameters":[{"name":"wipeMoney","in":"query","required":false,"schema":{"type":"boolean","description":"Also erase durably persisted MONEY records (ad purchases, KX- credits, prize entries, funding outbox…). Default false: reset restores the deterministic seed but financial history is re-overlaid afterwards — money records survive a sandbox reset unless explicitly wiped.","default":false,"title":"Wipemoney"},"description":"Also erase durably persisted MONEY records (ad purchases, KX- credits, prize entries, funding outbox…). Default false: reset restores the deterministic seed but financial history is re-overlaid afterwards — money records survive a sandbox reset unless explicitly wiped."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"reset":true}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}}}},"/sandbox/rollout-sweep":{"get":{"tags":["Sandbox"],"summary":"Is the rollout artifact sweep running on this pod?","description":"Liveness of the background check that re-proves every active wave.\n\nThis endpoint exists because the loop cannot otherwise be shown to be\nrunning. It logs only when it blocks a wave, and it blocks a wave only when\nthe artifact's bytes have moved, so a working sweep on a settled fleet emits\nnothing whatsoever — identical, from outside, to a loop that never started.\nAn operator asking \"is anything still watching for the overwrite that\nstranded 78 cabinets\" had no way to find out, which left the manual verify\nendpoint as the only artifact check anybody could point at.\n\n``pod`` is part of the answer, not decoration. Two replicas sit behind this\nService and only the advisory-lock leader sweeps, so one poll answers for\nwhichever pod it reached: expect exactly one pod with ``sweeps`` climbing and\nthe other accumulating ``followerSkips``. Both counters rising is a healthy\ndeployment; ``ticks`` stuck at 0 on any pod is a dead loop on that pod.","operationId":"rollout_sweep_status_sandbox_rollout_sweep_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sandbox/refund-sweep":{"get":{"tags":["Sandbox"],"summary":"Is the stranded-payment sweep running on this pod?","description":"Liveness of the background reconciliation that finds paid, never-vended orders.\n\nThis is the only thing that turns \"the shopper was charged and the cabinet\nthen went quiet\" into a refund an operator can see is owed. It logs only\nwhen it flags an order, so on a fleet with nothing stranded it emits nothing\nat all — indistinguishable from a loop that never started. That gap is worse\nthan the identical one on the rollout sweep, because what goes unwatched\nhere is captured money.\n\n``pod`` is part of the answer, not decoration. Two replicas sit behind this\nService and only the advisory-lock leader sweeps: expect exactly one pod\nwith ``sweeps`` climbing and the other accumulating ``followerSkips``.\n``ticks`` stuck at 0 on any pod is a dead loop on that pod, and\n``enabled: false`` is a deliberate disable rather than a fault.","operationId":"refund_sweep_status_sandbox_refund_sweep_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sandbox/dispense-decision":{"get":{"tags":["Sandbox"],"summary":"Is the dispense decision deadline being enforced?","description":"Liveness of the loop that stops a shopper waiting forever.\n\nThe refund sweep above is an accounting horizon that *flags* money as owed.\nThis is the shopper's clock: past ``timeoutSeconds`` a vend with no outcome\nis ruled failed and the money is actually returned. It has the same\nsilent-when-healthy problem and the same leader/follower split — expect one\npod with ``ticks`` climbing and ``resolved`` usually 0, and the other\naccumulating ``followerSkips``. ``ticks`` stuck at 0 means this pod is not\nenforcing any deadline, which is the exact condition that let order\n20260817231847597612 hold $3.49 with nothing ever ruling on it.","operationId":"dispense_decision_status_sandbox_dispense_decision_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sandbox/persistence":{"get":{"tags":["Sandbox"],"summary":"Durable money-persistence status","description":"Backend, active flag, per-store record counts, and write-failure\ncounter for the money-record mirror (app/persistence.py). ``backend:\nnone`` means the deployment is running pure in-memory (no DSN).","operationId":"persistence_status_sandbox_persistence_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/machines/{machineNo}/operator-view":{"get":{"tags":["Machines"],"summary":"Machine operator view (aggregate)","description":"Everything the machine-side operator view renders, in one call:\nmachine status, sales buckets, aisle stock with low/out/fault rollups,\nand the cross-product money view (screen ads, QuestX free-product\nprogram, multiplayer game). Machine-scoped where the data is per-machine;\nthe ads revenue split is fleet-level (same numbers as\n``GET /api/v1/campaigns/reports/summary``) with this machine's play\ncounts broken out.","operationId":"operator_view_aggregate_api_v1_machines__machineNo__operator_view_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/operator-qr":{"get":{"tags":["Machines"],"summary":"Printable operator-view QR (PNG)","description":"Kiosk-X-branded QR encoding this machine's hosted operator view\n(``/operator?machine=...``). Print it and stick it inside the service\ndoor — a tech at the machine scans it and lands on the machine-scoped\noperator view. Same generator as the play/advertise QRs (each wears the\nbrand of the product it opens; operator tooling is Kiosk-X house).","operationId":"operator_qr_api_v1_machines__machineNo__operator_qr_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":1024,"minimum":240,"default":640,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/oauth/token":{"post":{"tags":["OAuth"],"summary":"Token","description":"Issue an access token. Only ``client_credentials`` is supported.","operationId":"token_oauth_token_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_token_oauth_token_post"}}},"required":true},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","token_type":"Bearer","expires_in":3600,"scope":"machines:read machines:write inventory:read inventory:write orders:read"}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}}}}},"/api/v1/auth/login":{"post":{"tags":["Auth"],"summary":"Operator sign-in (Intelliverse identity)","description":"Sign in with an intelli-verse-x.ai account (or the sandbox demo\npassword) and receive a Bearer token for the Partner API.","operationId":"login_api_v1_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"token":"eyJhbGciOiJIUzI1NiIs...","tokenType":"Bearer","expiresIn":2592000,"scope":"machines:read machines:write inventory:read inventory:write orders:read commands:read commands:write","operator":{"email":"you@intelli-verse-x.ai","name":"Your Fleet","admin":false}}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}}}}},"/api/v1/auth/login/social":{"post":{"tags":["Auth"],"summary":"Operator sign-in (Google or Apple ID token)","description":"Verify a Google or Apple ID token and start the same MFA challenge\nas password login. Existing operators only — this does not create an\naccount. Apple tokens that omit email match a previously linked appleSub.","operationId":"login_social_api_v1_auth_login_social_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SocialLoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/me":{"get":{"tags":["Auth"],"summary":"Who am I","description":"Return the authenticated identity, its scope, fleet binding and currency.\n\nCurrency is here because it is a property of the signed-in operator, not of\nany one report: the console reads it once at boot and formats every amount\non every screen with it. A client that had to discover the currency from\nwhichever money endpoint it happened to call first would render the login\nscreen's first paint in the wrong symbol.\n\nA full admin gets ``null`` — they are not one operator, and the amounts they\nread are scoped per request. Those responses carry their own declaration.","operationId":"me_api_v1_auth_me_get","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"userId":"you@intelli-verse-x.ai","operatorEmail":"you@intelli-verse-x.ai","admin":false,"scopes":["machines:read","machines:write","inventory:read","inventory:write","orders:read"],"authMethod":"oauth_sandbox"}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/auth/credentials":{"get":{"tags":["Auth"],"summary":"List my API credentials","description":"API keys and OAuth clients issued to the signed-in operator (masked).\n\nFull secrets are only shown at issuance; this endpoint powers the console's\naccount screen so operators can see key IDs, scopes, and rate limits.","operationId":"credentials_api_v1_auth_credentials_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/access/me":{"get":{"tags":["Access management"],"summary":"Me","operationId":"me_api_v1_access_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/access/session":{"post":{"tags":["Access management"],"summary":"Session","operationId":"session_api_v1_access_session_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionCheck"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/access/groups":{"get":{"tags":["Access management"],"summary":"Groups","operationId":"groups_api_v1_access_groups_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Access management"],"summary":"Create Group","operationId":"create_group_api_v1_access_groups_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/access/assignment":{"get":{"tags":["Access management"],"summary":"Assignment","operationId":"assignment_api_v1_access_assignment_get","parameters":[{"name":"username","in":"query","required":true,"schema":{"type":"string","title":"Username"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Access management"],"summary":"Assign","operationId":"assign_api_v1_access_assignment_put","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Grant"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/auth/mfa/enroll/start":{"post":{"tags":["Auth"],"summary":"Begin TOTP enrollment","operationId":"enroll_start_api_v1_auth_mfa_enroll_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/auth/mfa/enroll/confirm":{"post":{"tags":["Auth"],"summary":"Confirm TOTP enrollment","operationId":"enroll_confirm_api_v1_auth_mfa_enroll_confirm_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/auth/mfa/verify":{"post":{"tags":["Auth"],"summary":"Verify a TOTP or SMS login code","operationId":"verify_api_v1_auth_mfa_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/auth/mfa/recovery":{"post":{"tags":["Auth"],"summary":"Sign in with a one-time recovery code","operationId":"recovery_api_v1_auth_mfa_recovery_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecoveryBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew":{"post":{"tags":["Crew"],"summary":"Create a new crew","description":"Create a crew owned by the authenticated operator.","operationId":"create_crew_api_v1_crew_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrewCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Create Crew Api V1 Crew Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew/mine":{"get":{"tags":["Crew"],"summary":"Get crews for current user","description":"List all crews the operator owns or is a member of.\n\nFirst visit auto-creates a default crew so Profile → Team is not empty\nfor a brand-new operator (no seed, no create button).","operationId":"get_my_crews_api_v1_crew_mine_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get My Crews Api V1 Crew Mine Get"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew/{crew_id}":{"get":{"tags":["Crew"],"summary":"Get crew details","description":"Get crew info (accessible to owner/admin/members).","operationId":"get_crew_api_v1_crew__crew_id__get","parameters":[{"name":"crew_id","in":"path","required":true,"schema":{"type":"string","title":"Crew Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Crew Api V1 Crew  Crew Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew/{crew_id}/invite":{"post":{"tags":["Crew"],"summary":"Invite a member to crew","description":"Invite an operator to join the crew (owner/admin only).","operationId":"invite_member_api_v1_crew__crew_id__invite_post","parameters":[{"name":"crew_id","in":"path","required":true,"schema":{"type":"string","title":"Crew Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrewInvite"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Invite Member Api V1 Crew  Crew Id  Invite Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew/accept-invite/{invite_id}":{"post":{"tags":["Crew"],"summary":"Accept crew invite","description":"Accept an invite and join the crew.","operationId":"accept_invite_api_v1_crew_accept_invite__invite_id__post","parameters":[{"name":"invite_id","in":"path","required":true,"schema":{"type":"string","title":"Invite Id"}},{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Accept Invite Api V1 Crew Accept Invite  Invite Id  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew/{crew_id}/members":{"get":{"tags":["Crew"],"summary":"List crew members","description":"List all members of a crew (crew members only).","operationId":"list_members_api_v1_crew__crew_id__members_get","parameters":[{"name":"crew_id","in":"path","required":true,"schema":{"type":"string","title":"Crew Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response List Members Api V1 Crew  Crew Id  Members Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew/{crew_id}/members/{member_email}/role":{"put":{"tags":["Crew"],"summary":"Update member role","description":"Change a member's role (owner/admin only).","operationId":"update_member_role_api_v1_crew__crew_id__members__member_email__role_put","parameters":[{"name":"crew_id","in":"path","required":true,"schema":{"type":"string","title":"Crew Id"}},{"name":"member_email","in":"path","required":true,"schema":{"type":"string","title":"Member Email"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrewMemberUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Update Member Role Api V1 Crew  Crew Id  Members  Member Email  Role Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crew/{crew_id}/members/{member_email}":{"delete":{"tags":["Crew"],"summary":"Remove member from crew","description":"Remove a member from the crew (owner/admin only).","operationId":"remove_member_api_v1_crew__crew_id__members__member_email__delete","parameters":[{"name":"crew_id","in":"path","required":true,"schema":{"type":"string","title":"Crew Id"}},{"name":"member_email","in":"path","required":true,"schema":{"type":"string","title":"Member Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Remove Member Api V1 Crew  Crew Id  Members  Member Email  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/restock":{"post":{"tags":["Restock"],"summary":"Create restock run","description":"Create a restock run for a machine in the crew's fleet.","operationId":"create_restock_run_api_v1_restock_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestockRunCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Create Restock Run Api V1 Restock Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"get":{"tags":["Restock"],"summary":"List restock runs for crew","description":"List all restock runs for the operator's crew, optionally filtered by status.","operationId":"list_restock_runs_api_v1_restock_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response List Restock Runs Api V1 Restock Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/restock/today":{"get":{"tags":["Restock"],"summary":"Today's restock stops","description":"Get today's restock runs (scheduled for today's date).","operationId":"today_restock_runs_api_v1_restock_today_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Today Restock Runs Api V1 Restock Today Get"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/restock/{run_id}":{"get":{"tags":["Restock"],"summary":"Get restock run details","description":"Get a specific restock run.","operationId":"get_restock_run_api_v1_restock__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Restock Run Api V1 Restock  Run Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Restock"],"summary":"Update restock run","description":"Update run status (pending → in_progress → completed) or assign tech.","operationId":"update_restock_run_api_v1_restock__run_id__put","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestockRunUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Update Restock Run Api V1 Restock  Run Id  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"delete":{"tags":["Restock"],"summary":"Cancel restock run","description":"Cancel a restock run (owner/admin only).","operationId":"cancel_restock_run_api_v1_restock__run_id__delete","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Cancel Restock Run Api V1 Restock  Run Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/map/fleet":{"get":{"tags":["Map"],"summary":"Fleet map pins (all machines)","description":"Get crew machines with GPS coords for map display.","operationId":"fleet_map_api_v1_map_fleet_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Fleet Map Api V1 Map Fleet Get"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/map/today-stops":{"get":{"tags":["Map"],"summary":"Today's restock stops on map","description":"Get today's restock runs with GPS for route planning.","operationId":"today_restock_map_api_v1_map_today_stops_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Today Restock Map Api V1 Map Today Stops Get"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/warehouse/inventory":{"get":{"tags":["Warehouse"],"summary":"Warehouse SKU inventory levels","description":"Get warehouse SKU stock levels for restock planning.","operationId":"warehouse_inventory_api_v1_warehouse_inventory_get","parameters":[{"name":"warehouse_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Warehouse Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Warehouse Inventory Api V1 Warehouse Inventory Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/warehouse/reserve":{"post":{"tags":["Warehouse"],"summary":"Reserve SKUs for restock run","description":"Reserve specific SKUs for a restock run (transitions available → reserved).","operationId":"reserve_skus_api_v1_warehouse_reserve_post","parameters":[{"name":"run_id","in":"query","required":true,"schema":{"type":"string","title":"Run Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"object"},"title":"Items"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Reserve Skus Api V1 Warehouse Reserve Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/warehouse/allocate":{"post":{"tags":["Warehouse"],"summary":"Allocate SKUs to machine","description":"Allocate (ship) SKUs from warehouse to machine during restock.","operationId":"allocate_skus_api_v1_warehouse_allocate_post","parameters":[{"name":"machine_no","in":"query","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"object"},"title":"Items"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Allocate Skus Api V1 Warehouse Allocate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/orders/summary":{"get":{"tags":["Orders"],"summary":"Get orders summary","description":"Total order count, revenue, per-machine breakdown, and period aggregates.\n\nTotals and byMachine cover shipped (delivered) orders only. ``periods``\naggregates the FULL order history server-side (no client-side row cap):\ndelivered gross, refund count/amount, and net for today / last 7 days /\nlast 30 days, with \"today\" anchored to the operator's local midnight.\nMonetary totals retain the currency recorded on each sale. Mixed history\nhas ``totalsAvailable=false`` and null aggregate amounts; ``byCurrency``\ncontains the separate totals. Periods and machines declare their own\ncurrency. Revenue retains the agreed receipt amount. Refunded amounts use\nthe money actually returned; disputed captures are reported separately by\ncurrency in ``settlementReconciliation``. Tax accounting is available only\nfor USD history.","operationId":"get_summary_api_v1_orders_summary_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":840,"minimum":-840},{"type":"null"}],"description":"Client UTC offset in minutes, east-positive (JS: -new Date().getTimezoneOffset()). Used so the 'today' period boundary matches the caller's local midnight. Omit it to use the operator's own time zone, which is the better answer: an offset cannot say when a day began on a morning the clocks moved.","title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes, east-positive (JS: -new Date().getTimezoneOffset()). Used so the 'today' period boundary matches the caller's local midnight. Omit it to use the operator's own time zone, which is the better answer: an offset cannot say when a day began on a morning the clocks moved."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"totalOrders":160,"totalRevenue":983.4,"byMachine":[{"machineNo":"866903013700011","orderCount":82,"revenue":497.18},{"machineNo":"866903013700022","orderCount":78,"revenue":486.22}]}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/orders":{"get":{"tags":["Orders"],"summary":"List orders","description":"Paginated order list, filterable by machine, time range, refund flag,\nand realness.\n\n``needsRefund=true`` is how an operator works the refund queue — the same\norders the machine health check only ever reported as a count. ``synthetic``\nfilters demo-replica orders so an operational queue can hide invented sales.","operationId":"list_orders_api_v1_orders_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"machineId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineid"}},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"startTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"}},{"name":"endTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime"}},{"name":"needsRefund","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter on the outstanding-refund flag. ``true`` is the operator's refund queue: orders that took money the customer is still owed (failed vend, no vend report, stock mismatch). ``false`` excludes them. Omitted returns both.","title":"Needsrefund"},"description":"Filter on the outstanding-refund flag. ``true`` is the operator's refund queue: orders that took money the customer is still owed (failed vend, no vend report, stock mismatch). ``false`` excludes them. Omitted returns both."},{"name":"includeReview","in":"query","required":false,"schema":{"type":"boolean","description":"With needsRefund=true, also include cash receipt, partial delivery, and pending finalization reviews whose refund amount is unknown. Other filters and tenant scope still apply.","default":false,"title":"Includereview"},"description":"With needsRefund=true, also include cash receipt, partial delivery, and pending finalization reviews whose refund amount is unknown. Other filters and tenant scope still apply."},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":20,"title":"Size"}},{"name":"synthetic","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter demo-replica orders. `false` leaves only orders a real customer paid for, which is what an operational queue wants; omit it to see everything.","title":"Synthetic"},"description":"Filter demo-replica orders. `false` leaves only orders a real customer paid for, which is what an operational queue wants; omit it to see everything."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"page":1,"size":20,"total":178,"records":[{"orderNumber":"20260809000000000345","machineNo":"866903013700011","aisleNo":6,"productName":"Peak Protein","quantity":1,"sellingPrice":4.99,"paidPrice":4.99,"payState":3,"payStatus":"shipped","payType":2,"payment":{"processor":"nayax","method":"card","terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","transactionId":"nyx_9f2c1a7d3e5b0846","settlementAccountId":"nyx-act-63f2a9c01b","settlementAccountName":"Superior Vending Co.","cardBrand":"visa","last4":"4242","authCode":"A1B2C3","amount":4.99,"currency":"USD","settlementStatus":"settled"},"buyTime":"2026-08-09T21:41:52.000+0000"}]}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/orders/reconcile-stranded":{"post":{"tags":["Orders"],"summary":"Reconcile stranded payments (admin)","description":"ADMIN: find paid orders whose machine never reported a dispense outcome,\nand return the money on everything the platform owes.\n\nA machine that goes offline between payment settlement and its vend report\nnever sends that report, so none of the dispense-failure paths fire and the\norder sits at ``paid`` with no outcome — a charge nobody is working. This\nsweep is the missing timeout: anything older than\n``KIOSKX_NO_VEND_TIMEOUT`` (override per call with ``olderThanSeconds``)\ngains ``dispenseFailed`` + ``needsRefund`` + reason ``no-vend-report``.\n\nIt then **returns the money**, on the newly flagged orders and on every\norder already carrying ``needsRefund`` from any other path. Flagging alone\nwas the defect: the flag has five writers and one clearer, and the clearer\nwas only ever reached by the 180-second decision loop, so orders flagged by\nanything else stayed flagged and stayed charged.\n\nIdempotent, and never touches an order that reached a terminal state\n(shipped, refunded, cancelled). Also runs on a timer in the background —\nsee ``KIOSKX_NO_VEND_SWEEP_INTERVAL``.","operationId":"reconcile_stranded_api_v1_orders_reconcile_stranded_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ReconcileStrandedRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/orders/delivered-unpaid":{"get":{"tags":["Orders"],"summary":"Product dispensed with no capture","description":"Every order across the fleet that released product with nothing to show\nit was paid for — the fleet-wide loss figure, on demand.\n\nAnswers a question that until now could only be asked with SQL against the\npersistence table, which is why nine free vends on ``866902661300036`` ran\nfor five days at $53.21 and were found during an unrelated investigation.\nThe sweep in ``settlement.flag_delivered_unpaid`` shouts about new ones and\nthe machine health card shows a cabinet's own; this is the total, so\nsomebody can answer \"how much have we given away\" without a database.\n\nRead-only. It reports, it never flags — the sweep owns the ruling, and two\nwriters of the same verdict is how a report and an alert start disagreeing.\nOperators see their own cabinets; admins see the fleet.\n\n``olderThanSeconds`` overrides the grace period, and ``0`` shows the raw\nstate including sales whose reader settlement is still legitimately in\nflight. Useful for reconciling against a processor report; misleading as an\nalert, which is why the default is the grace period and not zero.","operationId":"delivered_unpaid_api_v1_orders_delivered_unpaid_get","parameters":[{"name":"olderThanSeconds","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Olderthanseconds"}},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/orders/{orderNumber}/refund":{"post":{"tags":["Orders"],"summary":"Refund an order","description":"Refund a paid or shipped order back to the customer — money first.\n\nThe payout is attempted against the processor that took the money BEFORE\nanything is written to the ledger, and the order is only marked ``refunded``\n(payState 4, settlement ``refunded``, ``needsRefund`` cleared) once that\npayout is real. A failed payout returns non-200, records ``refundError``,\nand KEEPS ``needsRefund`` set so the order stays in the refund queue.\n\nKiosk-X can only pay out what it holds credentials for: Scan & Pay\n(Stripe) orders refund over the API, idempotently per order number. Nayax\ncard sales and cash have no outbound refund path here — those refuse with\ninstructions (issue it in Nayax Core / hand the cash back). Once the money\nIS back by other means, record it with ``external: true`` plus a required\n``externalReference``; that never happens by default.\n\nOrders that were never paid (pending with no capture, cancelled) or are\nalready refunded return 400. A pending order whose payment the processor\nhas already settled is refundable: the shopper was charged and got nothing.","operationId":"refund_order_api_v1_orders__orderNumber__refund_post","parameters":[{"name":"orderNumber","in":"path","required":true,"schema":{"type":"string","title":"Ordernumber"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/app__routes__orders__RefundRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/orders/{orderNumber}/refund-failure":{"post":{"tags":["Orders"],"summary":"Record a refund attempt that returned no money","description":"Tell the platform a refund attempt failed, and whether it can be retried.\n\nA transient failure leaves the order owing a refund, so it stays in the\noutstanding queue and the next attempt is welcome.\n\n``permanent`` is for the answer that cannot be retried: the provider has no\nrecord of the payment at all — a 404 against money it has forgotten for\ngood. That is terminal. The order leaves the retry queue and keeps an honest\nmark instead: it is not refunded, ``refundNotReturnedCents`` is what the\ncustomer did not get back, and a further attempt is refused with 409 rather\nthan adding one more line to a log that already cannot be acted on.","operationId":"record_refund_failure_api_v1_orders__orderNumber__refund_failure_post","parameters":[{"name":"orderNumber","in":"path","required":true,"schema":{"type":"string","title":"Ordernumber"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundFailureRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/orders/{orderNumber}":{"delete":{"tags":["Orders"],"summary":"Delete an order (admin)","description":"ADMIN-ONLY demo hygiene: permanently remove a bogus/test order.\n\nReal money history is corrected via the refund flow, never erased —\nthis exists so obviously-polluted sandbox records (e.g. a $999,999.99\nboundary-test vend) can be excised without resetting the whole fleet.","operationId":"delete_order_api_v1_orders__orderNumber__delete","parameters":[{"name":"orderNumber","in":"path","required":true,"schema":{"type":"string","title":"Ordernumber"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"get":{"tags":["Orders"],"summary":"Get order detail","description":"Returns a single order by order number.","operationId":"get_order_api_v1_orders__orderNumber__get","parameters":[{"name":"orderNumber","in":"path","required":true,"schema":{"type":"string","title":"Ordernumber"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"orderNumber":"20260809000000000345","machineNo":"866903013700011","aisleNo":6,"productName":"Peak Protein","quantity":1,"sellingPrice":4.99,"paidPrice":4.99,"payState":3,"payStatus":"shipped","payType":2,"payment":{"processor":"nayax","method":"card","terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","transactionId":"nyx_9f2c1a7d3e5b0846","settlementAccountId":"nyx-act-63f2a9c01b","settlementAccountName":"Superior Vending Co.","cardBrand":"visa","last4":"4242","authCode":"A1B2C3","amount":4.99,"currency":"USD","settlementStatus":"settled"},"buyTime":"2026-08-09T21:41:52.000+0000"}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/revenue/summary":{"get":{"tags":["Revenue"],"summary":"Fleet revenue summary — every stream","description":"Fleet-wide revenue across ALL streams — product sales, ads (self-serve\npurchases + direct campaigns + programmatic), games (paid prize entries +\nthe external ContentX worlds bridge), multiplayer games ($0-capable,\nwired), and funded quest redemptions — with a per-machine table.\n\nActual cash and estimates are totalled separately (``totalActualUsd`` /\n``totalEstimatedUsd``); external streams report their bridge signal, never\ninvented dollars.","operationId":"revenue_summary_api_v1_revenue_summary_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive","title":"From"},"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive"},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)","title":"To"},"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/revenue/machines/{machineNo}":{"get":{"tags":["Revenue"],"summary":"One machine's revenue, per stream","description":"Per-stream revenue breakdown for one machine, including the underlying\nrecent transactions (orders, ad purchases, paid prize entries, world\ncredit mints, funded redemptions) so every number traces to a record.","operationId":"machine_revenue_api_v1_revenue_machines__machineNo__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive","title":"From"},"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive"},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)","title":"To"},"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/leads":{"get":{"tags":["Operator CRM"],"summary":"List Leads","operationId":"list_leads_api_v1_crm_leads_get","parameters":[{"name":"unclaimed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Unclaimed"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator CRM"],"summary":"Create Lead","operationId":"create_lead_api_v1_crm_leads_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/leads/{lead_id}":{"patch":{"tags":["Operator CRM"],"summary":"Patch Lead","operationId":"patch_lead_api_v1_crm_leads__lead_id__patch","parameters":[{"name":"lead_id","in":"path","required":true,"schema":{"type":"string","title":"Lead Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/leads/{lead_id}/claim":{"post":{"tags":["Operator CRM"],"summary":"Claim Lead","operationId":"claim_lead_api_v1_crm_leads__lead_id__claim_post","parameters":[{"name":"lead_id","in":"path","required":true,"schema":{"type":"string","title":"Lead Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/venues":{"get":{"tags":["Operator CRM"],"summary":"List Venues","operationId":"list_venues_api_v1_crm_venues_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator CRM"],"summary":"Create Venue","operationId":"create_venue_api_v1_crm_venues_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VenueIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/venues/{venue_id}":{"patch":{"tags":["Operator CRM"],"summary":"Patch Venue","operationId":"patch_venue_api_v1_crm_venues__venue_id__patch","parameters":[{"name":"venue_id","in":"path","required":true,"schema":{"type":"string","title":"Venue Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/venues/{venue_id}/place":{"post":{"tags":["Operator CRM"],"summary":"Place Machine","description":"Move a machine to this venue. Statements the old host already earned\nare left alone; only future accrual follows the machine.","operationId":"place_machine_api_v1_crm_venues__venue_id__place_post","parameters":[{"name":"venue_id","in":"path","required":true,"schema":{"type":"string","title":"Venue Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlacementIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/venues/{venue_id}/release":{"post":{"tags":["Operator CRM"],"summary":"Release Machine","description":"End a placement. The venue and its past statements survive.","operationId":"release_machine_api_v1_crm_venues__venue_id__release_post","parameters":[{"name":"venue_id","in":"path","required":true,"schema":{"type":"string","title":"Venue Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_ledger__ReleaseIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/deals":{"get":{"tags":["Operator CRM"],"summary":"List Deals","operationId":"list_deals_api_v1_crm_deals_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator CRM"],"summary":"Create Deal","operationId":"create_deal_api_v1_crm_deals_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/deals/{deal_id}":{"patch":{"tags":["Operator CRM"],"summary":"Patch Deal","operationId":"patch_deal_api_v1_crm_deals__deal_id__patch","parameters":[{"name":"deal_id","in":"path","required":true,"schema":{"type":"string","title":"Deal Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/tasks":{"get":{"tags":["Operator CRM"],"summary":"List Tasks","operationId":"list_tasks_api_v1_crm_tasks_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator CRM"],"summary":"Create Task","operationId":"create_task_api_v1_crm_tasks_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/crm/tasks/{task_id}":{"patch":{"tags":["Operator CRM"],"summary":"Patch Task","operationId":"patch_task_api_v1_crm_tasks__task_id__patch","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/tax/schedules":{"get":{"tags":["Tax"],"summary":"List Tax","operationId":"list_tax_api_v1_tax_schedules_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Tax"],"summary":"Create Tax","operationId":"create_tax_api_v1_tax_schedules_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/tax/restatements-blocked":{"get":{"tags":["Tax"],"summary":"List Tax Restatements Blocked","description":"Rates the operator has set that a settled period is refusing to take.\n\nEmpty is the healthy answer. A non-empty row means a rate now in force —\ntypically a per-cabinet jurisdiction rate discovered after the fleet\nschedule was set — is NOT being applied to a month already remitted or paid\na host out on, so the operator can see the rate is not silently taking\neffect and why.","operationId":"list_tax_restatements_blocked_api_v1_tax_restatements_blocked_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/lots/":{"get":{"tags":["FIFO lots"],"summary":"List Lots","operationId":"list_lots_api_v1_inventory_lots__get","parameters":[{"name":"sku","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sku"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["FIFO lots"],"summary":"Receive Lot","operationId":"receive_lot_api_v1_inventory_lots__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LotIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/lots/consume":{"post":{"tags":["FIFO lots"],"summary":"Consume Lot","operationId":"consume_lot_api_v1_inventory_lots_consume_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsumeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payroll/":{"get":{"tags":["Payroll"],"summary":"Payroll View","operationId":"payroll_view_api_v1_payroll__get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payroll/rates":{"post":{"tags":["Payroll"],"summary":"Payroll Rate","operationId":"payroll_rate_api_v1_payroll_rates_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payroll/hours":{"post":{"tags":["Payroll"],"summary":"Payroll Hours","operationId":"payroll_hours_api_v1_payroll_hours_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoursIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payroll/payments":{"post":{"tags":["Payroll"],"summary":"Payroll Pay","operationId":"payroll_pay_api_v1_payroll_payments_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payouts/":{"get":{"tags":["Host payouts"],"summary":"Payouts View","operationId":"payouts_view_api_v1_payouts__get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Host payouts"],"summary":"Record Payout","operationId":"record_payout_api_v1_payouts__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payouts/statement":{"get":{"tags":["Host payouts"],"summary":"Host Statement","description":"The statement a host sees: how the commission was computed, and what\nhas been sent to their account (last 4 only).","operationId":"host_statement_api_v1_payouts_statement_get","parameters":[{"name":"venueId","in":"query","required":true,"schema":{"type":"string","title":"Venueid"}},{"name":"period","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/pnl/":{"get":{"tags":["P&L"],"summary":"Pnl View","operationId":"pnl_view_api_v1_pnl__get","parameters":[{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/expenses/":{"get":{"tags":["Expenses"],"summary":"List Expenses","description":"The operating-cost ledger, with the category split the P&L deducts.","operationId":"list_expenses_api_v1_expenses__get","parameters":[{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Expenses"],"summary":"Create Expense","operationId":"create_expense_api_v1_expenses__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/expenses/{expense_id}":{"delete":{"tags":["Expenses"],"summary":"Delete Expense","operationId":"delete_expense_api_v1_expenses__expense_id__delete","parameters":[{"name":"expense_id","in":"path","required":true,"schema":{"type":"string","title":"Expense Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/purchases/":{"get":{"tags":["Purchases"],"summary":"List Purchases","description":"Wholesaler orders, each with the FIFO lots it created.","operationId":"list_purchases_api_v1_purchases__get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Purchases"],"summary":"Create Purchase","description":"Receive stock. This is what CREATES the cost layers the P&L consumes.","operationId":"create_purchase_api_v1_purchases__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/purchases/{purchase_id}/pay":{"post":{"tags":["Purchases"],"summary":"Pay Purchase","operationId":"pay_purchase_api_v1_purchases__purchase_id__pay_post","parameters":[{"name":"purchase_id","in":"path","required":true,"schema":{"type":"string","title":"Purchase Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchasePayIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/restocks/":{"get":{"tags":["Restocks"],"summary":"List Restocks","description":"Service-visit history, plus what every machine is currently short of.","operationId":"list_restocks_api_v1_restocks__get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Restocks"],"summary":"Create Restock","description":"Move stock from the warehouse into named lanes.","operationId":"create_restock_api_v1_restocks__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestockIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/referrals/":{"get":{"tags":["Referral payouts"],"summary":"Referrals View","description":"Who introduced which venue, what they are owed, and what has been sent.","operationId":"referrals_view_api_v1_referrals__get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/referrals/payouts":{"post":{"tags":["Referral payouts"],"summary":"Record Referral Payout","operationId":"record_referral_payout_api_v1_referrals_payouts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralPayoutIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/balance-sheet/":{"get":{"tags":["Balance sheet"],"summary":"Balance Sheet","description":"Assets, liabilities and equity, every line derived from the ledger.","operationId":"balance_sheet_api_v1_balance_sheet__get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/breakdown/":{"get":{"tags":["Breakdown"],"summary":"Breakdown View","description":"Revenue and cost pivoted by machine, venue, product category or payment.","operationId":"breakdown_view_api_v1_breakdown__get","parameters":[{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/analytics/trend":{"get":{"tags":["Analytics"],"summary":"Trend","description":"The P&L month by month, each month read straight from the ledger.\n\nScoped exactly like every other books read: ``_op`` hands an operator\ncredential its own identity whatever it asks for, and only a full admin can\nnarrow to someone else with ``?operatorEmail=``.","operationId":"trend_api_v1_analytics_trend_get","parameters":[{"name":"months","in":"query","required":false,"schema":{"type":"integer","maximum":36,"minimum":1,"default":12,"title":"Months"}},{"name":"through","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Last month of the series, YYYY-MM. Defaults to the current month.","title":"Through"},"description":"Last month of the series, YYYY-MM. Defaults to the current month."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/factory-tests":{"get":{"tags":["Factory tests"],"summary":"Factory-test rollup (whole fleet)","description":"Admin-only manufacturing view: one row per machine with a factory\nrecord — latest pass/fail counts, run count and provenance.","operationId":"fleet_factory_tests_api_v1_machines_factory_tests_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/warehouse":{"get":{"tags":["Factory tests"],"summary":"USA warehouse inbound board (admin)","description":"Every factory serial, bucketed: line → ship → USA warehouse → install.\n\nSuper-admin only. Operators never see other people's inbound stock.\nPhoto print is optional on every row (``photoPrintAttached``).","operationId":"warehouse_board_api_v1_machines_warehouse_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/warehouse/receive":{"post":{"tags":["Factory tests"],"summary":"Mark a signed cabinet received at the USA warehouse","operationId":"warehouse_receive_api_v1_machines__machineNo__warehouse_receive_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/WarehouseReceiveBody"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/factory-certificate":{"get":{"tags":["Factory tests"],"summary":"Manufacturer acceptance certificate","description":"The signed factory certificate — what the USA warehouse checks\nbefore receiving a crate. Photo print is optional on the snapshot.","operationId":"machine_factory_certificate_api_v1_machines__machineNo__factory_certificate_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/factory-test":{"get":{"tags":["Factory tests"],"summary":"Factory-test history for one machine","description":"Latest factory report + up to 20 past runs + provenance, scoped the\nsame way as every other per-machine read.","operationId":"machine_factory_test_api_v1_machines__machineNo__factory_test_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/provenance":{"put":{"tags":["Factory tests"],"summary":"Set manufacturing provenance (admin)","description":"Admin-only: record who built the unit and when it shipped. Only the\nprovided fields change.","operationId":"put_provenance_api_v1_machines__machineNo__provenance_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvenanceBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/photobooth/sessions":{"get":{"tags":["Photobooth"],"summary":"Recent photobooth sessions on a machine","description":"The operator console's session log for one machine (newest first) —\nstate, premium/paid, prompt preview, result URL. Never triggers device\ntraffic or a ContentX poll.","operationId":"machine_photobooth_sessions_api_v1_machines__machineNo__photobooth_sessions_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/photobooth/sessions/{sessionId}/reprint":{"post":{"tags":["Photobooth"],"summary":"Queue a reprint of a finished photobooth photo","description":"Operator reprint from a stored result. Does not vend and does not\ncharge the shopper again — this is the moderator path.","operationId":"machine_photobooth_reprint_api_v1_machines__machineNo__photobooth_sessions__sessionId__reprint_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","title":"Sessionid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/logs":{"get":{"tags":["Device logs"],"summary":"Recent agent logs for one machine","operationId":"machine_logs_api_v1_machines__machineNo__logs_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1500,"minimum":1,"default":200,"title":"Limit"}},{"name":"level","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"minimum level","title":"Level"},"description":"minimum level"},{"name":"contains","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"substring filter","title":"Contains"},"description":"substring filter"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/telemetry":{"get":{"tags":["Device logs"],"summary":"Last raw device record (admin, unabridged)","description":"Whatever the device last reported, verbatim.\n\nDeliberately unshaped. Health checks summarise, and a summary is what you\nrun out of at the worst moment — the board check names eleven probed ports\nand prints one example error, which cannot answer \"were the other ten\nlocked out too?\".","operationId":"machine_telemetry_api_v1_machines__machineNo__telemetry_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines":{"get":{"tags":["Machines"],"summary":"List machines","description":"Machines for your account. Admin keys see all operators' machines.","operationId":"list_machines_api_v1_machines_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Admin only: filter by operator email","title":"Operatoremail"},"description":"Admin only: filter by operator email"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status: online or offline","title":"Status"},"description":"Filter by status: online or offline"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":20,"title":"Size"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"page":1,"size":20,"total":2,"records":[{"id":"8915eb33989a44ac8b9bdceac6df43e1","machineNo":"866903013700011","name":"Ryan Test","status":"online","lastSeen":"2026-08-10T11:49:00.000+0000","location":"Warehouse A","lat":"40.7128","lng":"-74.0060","notes":null,"expireDate":"2027-08-10T12:00:00.000+0000","rentState":1,"nayax":{"terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","model":"VPOS Touch","connection":"MDB","status":"active","merchantAccountId":"nyx-act-63f2a9c01b","merchantAccountName":"Superior Vending Co."}}]}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/register":{"post":{"tags":["Machines"],"summary":"Register a new machine","description":"Register (or claim) a freshly installed physical machine.\n\nTwo paths land here. If the serial has never been seen, the machine is\nprovisioned with ten empty aisles ready to price and refill. If the board\nalready powered on and auto-provisioned itself into the unclaimed pool,\nregistration *claims* it — the machine (and any vends it already took)\ntransfers into your fleet. Requires machines:write. Returns 409 only if\nthe serial belongs to another operator.","operationId":"register_machine_api_v1_machines_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineRegisterRequest"}}},"required":true},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"id":"8915eb33989a44ac8b9bdceac6df43e1","machineNo":"866903013700099","name":"Gym Lobby","status":"offline","lastSeen":null,"location":"Warehouse A","lat":"40.7128","lng":"-74.0060","notes":null,"expireDate":"2027-08-10T12:00:00.000+0000","rentState":1,"nayax":{"terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","model":"VPOS Touch","connection":"MDB","status":"active","merchantAccountId":"nyx-act-63f2a9c01b","merchantAccountName":"Superior Vending Co."}}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"409":{"description":"Conflict — resource already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":409,"message":"Machine number is already registered to another operator","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}":{"get":{"tags":["Machines"],"summary":"Get machine by number","description":"Single machine's details including last heartbeat time.","operationId":"get_machine_api_v1_machines__machineNo__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"id":"8915eb33989a44ac8b9bdceac6df43e1","machineNo":"866903013700011","name":"Ryan Test","status":"online","lastSeen":"2026-08-10T11:49:00.000+0000","location":"Warehouse A","lat":"40.7128","lng":"-74.0060","notes":null,"expireDate":"2027-08-10T12:00:00.000+0000","rentState":1,"nayax":{"terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","model":"VPOS Touch","connection":"MDB","status":"active","merchantAccountId":"nyx-act-63f2a9c01b","merchantAccountName":"Superior Vending Co."}}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Machines"],"summary":"Update machine (PUT alias)","description":"Update a machine's name, notes, and/or map location. Requires machines:write.\n\nTwo ways to pin the machine on the fleet map: explicit ``lat``/``lng``\n(e.g. Operator X using device GPS at install time), or an ``address``\nthat this API geocodes server-side (self-hosted Photon, OSM data) into\ncanonical coordinates + ``placeId``. Send either an address or a complete\ncoordinate pair. This legacy path records an unverified placement; use\naddress/check and address/confirm for explicit structured review.\n\nAn address the geocoder cannot place does **not** fail the update. The\nmachine is saved with the address as typed, no coordinates, and a\n``geo.geocodeStatus`` recording why — ``not_found`` when the geocoder\ngenuinely does not know it, ``provider_error`` when the geocoder was\nunreachable, ``skipped`` when this deployment has no geocoder configured.\nThe last two set ``geo.geocodeRetryable``; see the geocode/retry route.\n\nAn address is only half of a placement. ``venueId`` places the machine at a\nCRM venue in the same call, which is what actually starts its host earning\ncommission — without it the machine sells and nobody accrues anything, and\nnothing anywhere says so. ``hostArrangement: \"none\"`` is the other honest\nanswer, for a cabinet on premises the operator owns. Whichever is set, the\nresponse's ``hostLink`` block reports where the machine now stands, what has\nalready sold with no host attached, and which venues could be linked.","operationId":"update_machine_api_v1_machines__machineNo__put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"patch":{"tags":["Machines"],"summary":"Update machine","description":"Update a machine's name, notes, and/or map location. Requires machines:write.\n\nTwo ways to pin the machine on the fleet map: explicit ``lat``/``lng``\n(e.g. Operator X using device GPS at install time), or an ``address``\nthat this API geocodes server-side (self-hosted Photon, OSM data) into\ncanonical coordinates + ``placeId``. Send either an address or a complete\ncoordinate pair. This legacy path records an unverified placement; use\naddress/check and address/confirm for explicit structured review.\n\nAn address the geocoder cannot place does **not** fail the update. The\nmachine is saved with the address as typed, no coordinates, and a\n``geo.geocodeStatus`` recording why — ``not_found`` when the geocoder\ngenuinely does not know it, ``provider_error`` when the geocoder was\nunreachable, ``skipped`` when this deployment has no geocoder configured.\nThe last two set ``geo.geocodeRetryable``; see the geocode/retry route.\n\nAn address is only half of a placement. ``venueId`` places the machine at a\nCRM venue in the same call, which is what actually starts its host earning\ncommission — without it the machine sells and nobody accrues anything, and\nnothing anywhere says so. ``hostArrangement: \"none\"`` is the other honest\nanswer, for a cabinet on premises the operator owns. Whichever is set, the\nresponse's ``hostLink`` block reports where the machine now stands, what has\nalready sold with no host attached, and which venues could be linked.","operationId":"update_machine_api_v1_machines__machineNo__patch","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineUpdateRequest"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"id":"8915eb33989a44ac8b9bdceac6df43e1","machineNo":"866903013700011","name":"Lobby Kiosk","status":"online","lastSeen":"2026-08-10T11:49:00.000+0000","location":"Warehouse A","lat":"40.7128","lng":"-74.0060","notes":"Relocated to lobby","expireDate":"2027-08-10T12:00:00.000+0000","rentState":1,"nayax":{"terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","model":"VPOS Touch","connection":"MDB","status":"active","merchantAccountId":"nyx-act-63f2a9c01b","merchantAccountName":"Superior Vending Co."}}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/health/summary":{"get":{"tags":["Machines"],"summary":"Fleet health roll-up","description":"One-line health per owned machine — the fleet-list chips.\n\nSame nine checks as the per-machine endpoint, collapsed to\n``overall`` + per-state counts. Reads only device-pushed state (plus one\nshared, cached Stripe probe), so polling this never touches a machine.","operationId":"fleet_health_summary_api_v1_machines_health_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/health":{"get":{"tags":["Machines"],"summary":"Machine health (all checks)","description":"The nine health checks for one machine — identical schema for Reyeah\nand ZHZN hardware (only the transport check's source differs). Safe to\npoll: everything is served from state the device already pushes on its\nown cadence; operator poll frequency generates zero device traffic.","operationId":"get_machine_health_api_v1_machines__machineNo__health_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/reboot":{"post":{"tags":["Machines"],"summary":"Reboot the machine","description":"One button, both manufacturers.\n\n* **Reyeah** — MQTT push ``{type:\"12\", restartType:\"1\"}``; the stock\n  firmware reboots the device via MyManager.reboot() and self-protects by\n  ignoring the command mid-payment.\n* **ZHZN** — a ``reboot`` control command on the leased pending queue;\n  the agent acks through the exactly-once report path and then reboots\n  (device owner) or restarts the app. At most one reboot command is ever\n  outstanding, so double-clicks are harmless.\n\nA reboot handed to a cabinet that is not collecting work is reported as\n``queued`` (202), never as done — see :func:`_reboot_outcome`. A refusal\nanswers 409 (or 503 while the broker is down), never 200 — see\n:func:`_reboot_answer`.","operationId":"reboot_machine_api_v1_machines__machineNo__reboot_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/ota-check":{"post":{"tags":["Machines"],"summary":"Check for an app update now","description":"Take the published update now, without rebooting the cabinet.\n\nA machine only notices a rollout on its own OTA interval, and the only way\nto force it used to be the Reboot button — which can interrupt a shopper,\nand mid-vend is worse. This asks for the update instead:\n\n* **ZHZN** — queues an ``otaCheck`` control command. The agent runs its\n  check on the next poll; the download happens with the vend board free\n  and the install still waits for the board to go idle, so an update can\n  never land between a motor turn and its outcome being recorded.\n* **Reyeah** — pushes the active rollout's artifact over MQTT\n  (``type:\"2\"``); with no active rollout there is nothing to check for.\n\n``data.outcome`` is the answer and the status line agrees with it:\n``dispatched`` (200) the cabinet is polling and has the instruction,\n``queued`` (202) accepted but nobody is collecting it, ``noop`` (200)\nnothing newer is on offer, ``unsupported`` (409, or 503 while the broker is\ndown) this build or transport cannot be asked, and ``unsafe`` (409) asking\nwould strand a pre-1.0.10 agent's worker thread and take the cabinet off\nthe network. ``reason`` and ``remedy`` say which and what to do instead.","operationId":"ota_check_machine_api_v1_machines__machineNo__ota_check_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/nayax":{"post":{"tags":["Machines"],"summary":"Bind a real Nayax reader to a machine","description":"Onboard a physical Nayax VPOS reader: set the machine's real Device Number.\n\nRegistration provisions every machine with a *provisional* placeholder\nterminal; this endpoint replaces it with the reader's real Nayax Device\nNumber so settlement webhooks resolve to this machine by exact match.\nTerminal IDs are globally unique — binding one that is already wired to\nanother machine returns 409. Settlement remains force-routed from this\nbinding (never from webhook payloads). Requires machines:write; operators\ncan only bind readers to machines they own.","operationId":"bind_nayax_terminal_api_v1_machines__machineNo__nayax_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NayaxBindRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"get":{"tags":["Machines"],"summary":"Get a machine's Nayax terminal binding","description":"The Nayax reader bound to this machine, including ``provisional`` state.","operationId":"get_nayax_terminal_api_v1_machines__machineNo__nayax_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/nayax/card-retest":{"post":{"tags":["Machines"],"summary":"Advertise the Credit card tile again, to prove a reader fix","description":"Put the Credit card tile back on a cabinet whose reader stopped capturing.\n\nA cabinet that takes a run of card taps and captures none of them loses the\ntile (``/apk/getEquipment`` serves ``isCard: 0``), because a tile that takes\na tap and settles nothing leaves the shopper believing they have paid. That\nverdict does not expire on its own: nothing about elapsed time indicates a\nreader was repaired, and the tile is the only thing that produces the taps\nthe verdict reads, so a timed reprieve just re-lights a dead reader on a\nloop.\n\nThis is the way back. It says \"something at the machine has changed — a\nNayax Core profile, the MDB harness, a replacement reader — advertise the\ncard again so a real tap can settle it\". The next run of taps decides: one\nreal capture and the tile stays for good, another run of nothing and it is\nwithdrawn again. So the cost of being wrong is bounded and chosen.\n\nDeliberately separate from binding a reader. ``POST .../nayax`` says which\nreader this is and is rewritten routinely, including while diagnosing a\ncabinet; treating that as a repair claim would re-light the tile on the\nstrength of somebody looking at the machine.\n\nRequires machines:write; operators can only do this to machines they own.","operationId":"arm_nayax_card_retest_api_v1_machines__machineNo__nayax_card_retest_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/decommission":{"post":{"tags":["Machines"],"summary":"Decommission a machine","description":"Retire a machine from your fleet (end of life, or transfer to another operator).\n\nThe serial returns to the unclaimed pool: the Nayax binding is cleared\nback to an inactive provisional placeholder (freeing the physical\nreader's Device Number), the machine goes offline, and your order\nhistory stays on your books. To *transfer* the unit, the receiving\noperator simply claims the same serial via ``POST\n/api/v1/machines/register`` — prior revenue does not follow the machine.\nRequires machines:write; operators can only decommission machines they own.\n\n**The cabinet also leaves your balance sheet, as a disposal**, so send\n``proceedsUsd`` if you got anything for it. Without it the disposal books\nat zero proceeds and the whole net book value is a loss, which is right for\na write-off and wrong by the sale price for a cabinet you sold — this route\nused to accept no body at all, so a $400 sale of a cabinet worth $599.90\nbooked a $599.90 loss instead of a $199.90 one.\n\nSame end of life as ``POST /api/v1/machines/{machineNo}/lifecycle/retire``,\nwhich is the longer form: it distinguishes ``resold``/``returned`` from a\nplain retirement, takes a reason, and returns the gain or loss inline.\nReach for that one when the distinction matters; this one is the short\nversion and books ``mode: retired``.","operationId":"decommission_machine_api_v1_machines__machineNo__decommission_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/DecommissionRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/address/check":{"post":{"tags":["Machines"],"summary":"Check a structured address without moving the cabinet","operationId":"check_machine_address_api_v1_machines__machineNo__address_check_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/address/confirm":{"post":{"tags":["Machines"],"summary":"Confirm a reviewed geocoder address match","operationId":"confirm_machine_address_api_v1_machines__machineNo__address_confirm_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/address/installation":{"post":{"tags":["Machines"],"summary":"Record an operator's on-site placement attestation","operationId":"confirm_machine_installation_api_v1_machines__machineNo__address_installation_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/geocode/retry":{"post":{"tags":["Machines"],"summary":"Retry an unresolved address","description":"Re-attempt the pin for a machine whose address never resolved.\n\nTwo situations this exists for. A geocoder outage leaves machines at\n``provider_error`` through no fault of the address, and they need a way\nback onto the map that is not \"edit every one by hand\". And an address the\nindex genuinely does not know may simply be typed wrong, so an operator\nneeds to supply a correction without hunting for the original field.\n\nPassing ``address`` retries that instead, and replaces the stored query —\nwhich is the only route back for ``not_found``, since re-asking the same\ngeocoder the same question cannot produce a different answer.","operationId":"retry_machine_geocode_api_v1_machines__machineNo__geocode_retry_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/GeocodeRetryRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/clock":{"get":{"tags":["Machines"],"summary":"The cabinet's clock, and how to change it","description":"Which wall clock this cabinet's screen shows, why, and what else it could.\n\n``timeZoneSource`` names the winning tier — ``machine`` (an operator said\nso), ``placement`` (derived from the stored country or US state) or\n``device`` (the cabinet's own OS zone) — and ``refusal`` says why a\ncandidate was thrown away. ``trust.state`` is the separate question of\nwhether the cabinet's own clock has been measured against ours; a cabinet\nwith a perfectly good zone still shows nothing until it has.\n\n``candidates`` is a shortlist worth offering: the recorded zone, the derived\none, the cabinet's own, then zones whose offset is possible at this\nlongitude. ``zones`` is the whole tz database for the operator who knows\nexactly what they want. Requires machines:read.","operationId":"machine_clock_api_v1_machines__machineNo__clock_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/age-verification":{"get":{"tags":["Machines"],"summary":"Age-verification policy, stats and recent events for a machine","description":"Everything Operator X's machine detail needs for the Didit gate: the\nnormalized policy, a vertical-derived suggestion (vape/alcohol machines\nget an ON suggestion), pass/fail/error counts, the most recent\nverification events (no PII — outcome + threshold + timestamp + session\nref only), and the machine's verification QR/entry URLs for the\ncard-reader path. Requires machines:read.","operationId":"age_verification_detail_api_v1_machines__machineNo__age_verification_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/events":{"get":{"tags":["Machine events & screen"],"summary":"Unified machine event timeline","description":"Everything that happened on one machine, newest first — orders,\nremote commands, faults, device logs, app analytics, operator actions\nand screen captures — regardless of manufacturer.","operationId":"machine_events_api_v1_machines__machineNo__events_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"types","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"csv filter, e.g. order,fault","title":"Types"},"description":"csv filter, e.g. order,fault"},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO timestamp lower bound","title":"Since"},"description":"ISO timestamp lower bound"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/features":{"get":{"tags":["Machine events & screen"],"summary":"Per-machine feature flags","description":"Heavy agent features (remote screen, app analytics) are OFF by default\nso the machine's APK stays lean — this is where an operator sees what is\nswitched on for one machine. ``delivered`` says whether the cabinet has\ncollected these flags or is merely the address they are waiting at.","operationId":"get_features_api_v1_machines__machineNo__features_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Machine events & screen"],"summary":"Enable/disable machine features","description":"Toggle a feature on one machine. A cabinet that is beating learns\nwithin one heartbeat (~60 s) — no restart, no new APK — and one that is\nnot is told so by ``delivered`` rather than being reported as switched.\nDisabling ``remoteScreen`` also ends any live-view session immediately.","operationId":"put_features_api_v1_machines__machineNo__features_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeaturesBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/agent-config":{"get":{"tags":["Machine events & screen"],"summary":"Agent hardware overrides","description":"Operator-set hardware knobs for one machine (serial port, baud, tray\nlayout). The primary use: a cabinet whose vend board answers on a\ndifferent UART than the agent default — set ``serialPort`` here and\nreboot the machine instead of driving out with a laptop. ``effective`` is\nwhat the cabinet will be handed on its next poll; ``delivered`` says\nwhether it has been there to take it.","operationId":"get_agent_config_api_v1_machines__machineNo__agent_config_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Machine events & screen"],"summary":"Set agent hardware overrides","description":"Set (or clear, with null) per-cabinet overrides. The agent reads\n``/zhzn/config`` once, at boot, so every key here takes effect at the\ncabinet's next start — queue a reboot from the machine page.","operationId":"put_agent_config_api_v1_machines__machineNo__agent_config_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/screen":{"get":{"tags":["Machine events & screen"],"summary":"Screen state: latest frame + support","operationId":"screen_state_api_v1_machines__machineNo__screen_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/screen/frames/{captureId}":{"get":{"tags":["Machine events & screen"],"summary":"Read a private screen frame","operationId":"screen_frame_api_v1_machines__machineNo__screen_frames__captureId__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"captureId","in":"path","required":true,"schema":{"type":"string","title":"Captureid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/screen/capture":{"post":{"tags":["Machine events & screen"],"summary":"Capture the screen once","description":"Ask the cabinet for one fresh frame; it lands asynchronously.\n\n``data.outcome`` is the answer and the status line agrees with it:\n``dispatched`` (200) the cabinet is polling and has the instruction,\n``queued`` (202) stored but nobody is collecting it, ``unsupported`` (409)\nnothing on this machine can serve a screen. ``reason`` and ``remedy`` say\nwhich and what to do about it.","operationId":"screen_capture_api_v1_machines__machineNo__screen_capture_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/screen/live":{"post":{"tags":["Machine events & screen"],"summary":"Start/stop the live view","description":"While a live session is active the agent uploads a frame every\n``interval`` seconds (it learns about the session on its next poll /\nheartbeat). Sessions self-expire — an operator can never leave a\nmachine streaming forever.\n\nAnswers in the same ``outcome`` vocabulary as the capture and OTA buttons,\nwith the status line derived from it: ``dispatched`` (200), ``queued`` (202)\nwhen the cabinet is not collecting work, ``unsupported`` (409) when nothing\non the machine can serve a screen.","operationId":"screen_live_api_v1_machines__machineNo__screen_live_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/screen/input":{"post":{"tags":["Machine events & screen"],"summary":"Send remote input","description":"Remote-drive the machine's screen. The agent injects the gesture into\nits own UI (ZHZN kiosk app / Reyeah companion overlay) and, when a live\nsession is running, the next frame shows the result.","operationId":"screen_input_api_v1_machines__machineNo__screen_input_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InputBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/camera":{"get":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Camera live view: support + latest frame","operationId":"camera_state_api_v1_machines__machineNo__camera_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/camera/live":{"post":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Start/stop the camera live view","description":"While a session is active the cabinet uploads a frame every ``interval``\nseconds; sessions self-expire so an operator can never leave a camera\nstreaming. Stopping is gateway-side state and always succeeds.","operationId":"camera_live_api_v1_machines__machineNo__camera_live_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CameraLiveBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/camera/snapshot":{"post":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"One camera frame now, analysed","description":"A six-second, one-frame-per-second session whose first frame is\nanalysed by the vision model. The frame and its description land\nasynchronously; poll ``GET …/camera`` and ``GET …/vision``.","operationId":"camera_snapshot_api_v1_machines__machineNo__camera_snapshot_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/announcements":{"get":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Announcement queue + support","operationId":"announcements_api_v1_machines__machineNo__announcements_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":40,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/announce":{"post":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Speak a line on the cabinet","operationId":"announce_text_api_v1_machines__machineNo__announce_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnounceBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/announce/clip":{"post":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Play a recorded clip on the cabinet (push-to-talk)","description":"Body is the audio itself (``Content-Type: audio/webm`` etc., ≤2 MB) —\nwhat a phone's MediaRecorder hands over — or JSON\n``{\"clipBase64\", \"contentType\", \"durationMs\"}`` for clients that cannot\npost a raw blob.","operationId":"announce_clip_api_v1_machines__machineNo__announce_clip_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"durationMs","in":"query","required":false,"schema":{"type":"integer","maximum":60000,"minimum":0,"default":0,"title":"Durationms"}},{"name":"volume","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":0},{"type":"null"}],"title":"Volume"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/announce/{annId}":{"get":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Delivery status of one announcement","operationId":"announce_status_api_v1_machines__machineNo__announce__annId__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"annId","in":"path","required":true,"schema":{"type":"string","title":"Annid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/vision":{"get":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Detection history: settings, summary, events","operationId":"vision_state_api_v1_machines__machineNo__vision_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":336,"minimum":1,"default":24,"title":"Hours"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Vision watch settings","description":"``watch`` only takes effect while the ``visionWatch`` and ``cameraLive``\nflags are on for the machine; the answer says whether it is actually\nwatching so a saved toggle can never read as a running camera.","operationId":"vision_settings_api_v1_machines__machineNo__vision_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisionBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/vision/analyze":{"post":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Describe the newest frame now","description":"Runs the vision model on the newest stored frame (any age) and records\nthe event. For a fresh picture use ``POST …/camera/snapshot`` instead.","operationId":"vision_analyze_api_v1_machines__machineNo__vision_analyze_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/camera/history":{"delete":{"tags":["Cabinet ops: camera, announce, vision"],"summary":"Delete every captured frame and detection event for this machine","description":"Pictures of the public are not kept because nobody got round to\nremoving them. This removes every stored frame (storage objects, by\nprefix, so nothing an old record forgot survives) and every\ndetection-history event for the machine on every replica, stops a live\nsession if one is running, and audits who did it. Always succeeds; the\ncounts say what was there.","operationId":"camera_history_delete_api_v1_machines__machineNo__camera_history_delete","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/cabinet-qa/sessions":{"post":{"tags":["Cabinet QA"],"summary":"Enable safe QA and mint a test URL","description":"Return the signed URL consumed by the QA APK's ephemeral bootstrap.\n\nThe URL is never embedded in an APK. Access remains operator-scoped and the\nselected cabinet is explicitly placed into visible, no-money/no-vend mode\nbefore the credential is returned.","operationId":"create_qa_session_api_v1_cabinet_qa_sessions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QaSessionBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/cabinet-qa/experiments":{"get":{"tags":["Cabinet QA"],"summary":"List presentation experiments","operationId":"list_experiments_api_v1_cabinet_qa_experiments_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Cabinet QA"],"summary":"Create presentation experiment","operationId":"create_experiment_api_v1_cabinet_qa_experiments_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/cabinet-qa/experiments/{experimentId}/summary":{"get":{"tags":["Cabinet QA"],"summary":"Experiment assignment and event summary","operationId":"experiment_summary_api_v1_cabinet_qa_experiments__experimentId__summary_get","parameters":[{"name":"experimentId","in":"path","required":true,"schema":{"type":"string","title":"Experimentid"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/cabinet-qa/experiments/{experimentId}/assignments":{"get":{"tags":["Cabinet QA"],"summary":"Persisted machine experiment assignments","operationId":"experiment_assignments_api_v1_cabinet_qa_experiments__experimentId__assignments_get","parameters":[{"name":"experimentId","in":"path","required":true,"schema":{"type":"string","title":"Experimentid"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/tray-survey":{"get":{"tags":["Tray survey"],"summary":"Tray survey state","description":"What is known about this cabinet's shelves, and the questions to ask.\n\n``planogram.established`` is the field that tells an operator whether the\naisle set they are looking at was counted or assumed.","operationId":"get_tray_survey_api_v1_machines__machineNo__tray_survey_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Tray survey"],"summary":"Record a tray survey","description":"Record what an operator counted at the cabinet.\n\n``shelves`` is one coil count per shelf, top shelf first. Pass\n``rebuildPlanogram: true`` to bring the aisle set to the surveyed size in\nthe same call; without it a survey that disagrees with the planogram is\nrefused rather than stored, because storing it would leave two incompatible\nsizes on file with the newer one looking authoritative for having been typed\nby a human.","operationId":"put_tray_survey_api_v1_machines__machineNo__tray_survey_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"delete":{"tags":["Tray survey"],"summary":"Withdraw a tray survey","description":"Withdraw a survey — the cabinet goes back to reporting an assumed layout.\n\nFor a survey taken against the wrong cabinet. Overwriting the counts would\nkeep the geometry established, and a survey somebody now believes was of the\nmachine next door is worth less than no survey at all.","operationId":"delete_tray_survey_api_v1_machines__machineNo__tray_survey_delete","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/tray-survey/preview":{"post":{"tags":["Tray survey"],"summary":"What a survey would change","description":"Dry-run a survey: validates the counts and states what rebuilding the\nplanogram to match would do. Writes nothing.\n\nExists so the rebuild is never the first time an operator learns it will\ndiscard a stock count.","operationId":"preview_tray_survey_api_v1_machines__machineNo__tray_survey_preview_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/tray-survey/undo-rebuild":{"post":{"tags":["Tray survey"],"summary":"Undo the last planogram rebuild","description":"Put the planogram back as it was before the survey rebuilt it.\n\nThe survey itself stands — the counts were still taken at the cabinet. This\nundoes only the consequence an operator may not have wanted.","operationId":"undo_rebuild_api_v1_machines__machineNo__tray_survey_undo_rebuild_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/manufacturer-setup":{"get":{"tags":["Tray survey"],"summary":"Reported manufacturer walkthrough","operationId":"get_manufacturer_setup_api_v1_machines__machineNo__manufacturer_setup_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/admin-pin":{"get":{"tags":["Machine security"],"summary":"This machine's admin PIN","description":"The PIN that exits kiosk mode on one cabinet.\n\nReading this issues one if the machine does not have a PIN yet, so an\noperator is never shown a blank where the answer is \"the fleet default\".","operationId":"get_admin_pin_api_v1_machines__machineNo__admin_pin_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Machine security"],"summary":"Set or rotate the admin PIN","description":"Choose this cabinet's PIN, or ask for a new random one.\n\nThe cabinet applies it on its next config poll — within a heartbeat for a\nmachine that is collecting work, and not at all until it reconnects for one\nthat is not. ``delivered`` says which of those this is rather than letting\nthe operator assume the first.","operationId":"put_admin_pin_api_v1_machines__machineNo__admin_pin_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPinBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/device-identity":{"get":{"tags":["Machine security"],"summary":"This machine's device key","description":"Which credential this cabinet authenticates with, and its history.\n\n``authenticatesWith: fleetSecret`` is not an error state — it is every\ncabinet that has not taken the agent build that enrols. It does mean this\nmachine's access cannot be revoked on its own, which is the thing an\noperator is usually here to check.","operationId":"get_device_identity_api_v1_machines__machineNo__device_identity_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/device-identity/revoke":{"post":{"tags":["Machine security"],"summary":"Revoke this machine's device key","description":"Stop accepting this cabinet's key from the next call onwards.\n\n``allowReenrolment`` defaults to false and that default is the feature. A\nstolen cabinet holds the same publicly downloadable APK as every other, so\nleaving the door open for it to enrol again would make revocation a\ngesture. Turn it on for the honest case — a unit that was reflashed, or\nwhose key file was lost — and the same machine comes back with a new key\nwithin a day.","operationId":"revoke_device_identity_api_v1_machines__machineNo__device_identity_revoke_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/device-identity/allow-reenrolment":{"post":{"tags":["Machine security"],"summary":"Let this machine enrol again","description":"Open a bounded window for a cabinet that lost its key.\n\nThe rescue route for a machine that is running and trusted but can no\nlonger prove who it is — the state the on-device key file exists to prevent\nand does not always. Bounded in time: an operator who opens one and forgets\nwould otherwise have removed the one-key-per-cabinet bound permanently.","operationId":"allow_reenrolment_api_v1_machines__machineNo__device_identity_allow_reenrolment_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/fleet/device-identity":{"get":{"tags":["Machine security"],"summary":"How far the fleet has migrated","description":"Which cabinets still authenticate with the credential they all share.\n\nThe number the decision to stop accepting the fleet secret has to be taken\non. Turning it off is a flag day for anything still relying on it, and this\nfleet's worst outages have come from believing every machine had updated —\nso the list of machines still using it is reported, not just the count.\n\n``stillOnFleetSecret`` counts only cabinets the gateway has actually heard\nfrom. A machine that has been unplugged for a month is in neither column,\nwhich is the honest answer and not a reassuring one: it will come back\npresenting whatever it was built with.","operationId":"fleet_device_identity_api_v1_fleet_device_identity_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/geo/geocode":{"get":{"tags":["Geo"],"summary":"Forward geocode (address → coordinates)","description":"Street address → canonical ``{lat, lng, formattedAddress, placeId}``.\n\nSame resolver the machine PATCH address path uses, exposed directly so\nmap clients (web console search box) can geocode without writing.","operationId":"forward_api_v1_geo_geocode_get","parameters":[{"name":"address","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":255,"title":"Address"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/geo/reverse":{"get":{"tags":["Geo"],"summary":"Reverse geocode (coordinates → address)","description":"Pin-move flows: the operator drags a pin, we answer with the nearest\naddress so the machine's location label stays human-readable.","operationId":"reverse_api_v1_geo_reverse_get","parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","maximum":90.0,"minimum":-90.0,"title":"Lat"}},{"name":"lng","in":"query","required":true,"schema":{"type":"number","maximum":180.0,"minimum":-180.0,"title":"Lng"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/geo/search":{"get":{"tags":["Geo"],"summary":"POI search (venues of a type near a point)","description":"Answer questions like \"how many schools within 3 miles of this corner?\"\nfrom the self-hosted OSM index. ``type`` accepts the Location Scout venue\ntaxonomy (see VENUE_TYPES) or a raw ``key:value`` OSM tag.","operationId":"search_api_v1_geo_search_get","parameters":[{"name":"type","in":"query","required":true,"schema":{"type":"string","description":"Venue type slug (school, gym, cafe, ...) or raw OSM tag key:value","title":"Type"},"description":"Venue type slug (school, gym, cafe, ...) or raw OSM tag key:value"},{"name":"near","in":"query","required":true,"schema":{"type":"string","description":"Center as 'lat,lng'","title":"Near"},"description":"Center as 'lat,lng'"},{"name":"radius","in":"query","required":false,"schema":{"type":"number","maximum":80.0,"exclusiveMinimum":0.0,"description":"Radius in km","default":4.8,"title":"Radius"},"description":"Radius in km"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory":{"get":{"tags":["Inventory"],"summary":"Get bulk inventory","description":"Inventory for multiple machines keyed by machineNo. Omit machineNos for all.","operationId":"bulk_inventory_api_v1_inventory_get","parameters":[{"name":"machineNos","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Machinenos"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"866903013700011":[{"machineNo":"866903013700011","aisleNo":1,"productName":"Aurora Water","currentStock":7,"maxStock":10,"sellingPrice":5.99,"faulted":false}]}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}":{"get":{"tags":["Inventory"],"summary":"Get machine inventory","description":"All aisles for a machine with stock, capacity, price, and fault status.","operationId":"machine_inventory_api_v1_inventory_machines__machineNo__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":[{"aisleNo":1,"productName":"Aurora Water","productCode":"DRK-SW","productImageUrl":"https://intelli-verse-x-media.s3.us-east-1.amazonaws.com/kiosk-x/products/prod-drk-sw.png","currentStock":7,"maxStock":10,"alertThreshold":2,"sellingPrice":5.99,"faulted":false}]}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/restock":{"post":{"tags":["Inventory"],"summary":"Restock machine","description":"Set aisles to max stock. Empty/omitted body restocks all. Requires inventory:write.\n\nLoading a lane moves stock the operator already owns into the machine — it\nnever consumes a FIFO cost layer, because cost is recognised when the item\nsells. The units moved are logged as a service visit so the Restocks screen\nshows the same route history whichever endpoint filled the lanes.","operationId":"restock_api_v1_inventory_machines__machineNo__restock_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RestockRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":[{"machineNo":"866903013700011","aisleNo":1,"productName":"Aurora Water","currentStock":10,"maxStock":10,"sellingPrice":5.99,"faulted":false}]}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/aisles/{aisleNo}":{"put":{"tags":["Inventory"],"summary":"Update aisle","description":"Update stock, price, alert threshold, or fault status. Requires inventory:write.","operationId":"update_aisle_api_v1_inventory_machines__machineNo__aisles__aisleNo__put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"aisleNo","in":"path","required":true,"schema":{"type":"integer","title":"Aisleno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AisleUpdateRequest"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"machineNo":"866903013700011","aisleNo":1,"productName":"Aurora Water","currentStock":7,"maxStock":10,"sellingPrice":6.49,"faulted":false,"alertThreshold":2}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/fulfill":{"post":{"tags":["Hybrid Fulfillment"],"summary":"Hybrid fulfill (walkup or api_drop)","description":"Route fulfillment by channel.\n\n* ``walkup`` — on-machine payment/dispense; cloud does **not** command motors.\n* ``api_drop`` — enqueue a remote dispense for the KioskX device agent.","operationId":"fulfill_api_v1_fulfill_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FulfillRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/commands/dispense":{"post":{"tags":["Hybrid Fulfillment"],"summary":"Enqueue remote dispense","description":"Cloud → queue a motor drop. Machine agent polls pending and executes.","operationId":"enqueue_dispense_api_v1_machines__machineNo__commands_dispense_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DispenseCommandRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/commands/pending":{"get":{"tags":["Hybrid Fulfillment"],"summary":"List pending dispense commands","description":"Device agent poll: returns pending api_drop commands oldest-first.","operationId":"list_pending_commands_api_v1_machines__machineNo__commands_pending_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/commands/{commandId}":{"get":{"tags":["Hybrid Fulfillment"],"summary":"Get dispense command status","operationId":"get_command_api_v1_machines__machineNo__commands__commandId__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"commandId","in":"path","required":true,"schema":{"type":"string","title":"Commandid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/commands/{commandId}/ack":{"post":{"tags":["Hybrid Fulfillment"],"summary":"Ack dispense command result","description":"Device agent reports motor result. Success decrements stock + ships an order.","operationId":"ack_command_api_v1_machines__machineNo__commands__commandId__ack_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"commandId","in":"path","required":true,"schema":{"type":"string","title":"Commandid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AckCommandRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payments/summary":{"get":{"tags":["Payments (Nayax)"],"summary":"Settlement summary by Nayax account","description":"Card/wallet takings grouped by the Nayax merchant account they settled to.\n\nThis is the reconciliation view: each row is one Nayax account with the\nterminals feeding it and the total settled amount — an operator can check\nit against their Nayax Core payout report line by line.\n\nOnly ``settled`` transactions count toward ``settledAmount``; device-reported\ncard sales awaiting webhook confirmation are broken out separately as\n``pendingCount`` / ``pendingAmount`` so unconfirmed money is never mixed in.","operationId":"payments_summary_api_v1_payments_summary_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"accounts":[{"settlementAccountId":"nyx-act-63f2a9c01b","settlementAccountName":"Superior Vending Co.","transactionCount":64,"settledAmount":391.36,"terminals":["NYX903013700011","NYX903013700022"]}]}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payments/nayax/terminals":{"get":{"tags":["Payments (Nayax)"],"summary":"List Nayax terminal bindings","description":"Machine → Nayax reader → merchant account mapping for your fleet.\n\nOne row per machine: the reader model and serial, its Nayax terminal ID\n(Device Number), and the merchant account its takings settle to.","operationId":"nayax_terminals_api_v1_payments_nayax_terminals_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"terminals":[{"terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","model":"VPOS Touch","connection":"MDB","status":"active","merchantAccountId":"nyx-act-63f2a9c01b","merchantAccountName":"Superior Vending Co.","machineNo":"866903013700011","machineName":"Ryan Test"}]}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payments/nayax/webhook":{"post":{"tags":["Payments (Nayax)"],"summary":"Nayax transaction webhook (HMAC-signed)","description":"Endpoint Nayax's cloud calls when a cashless transaction settles.\n\nAuthentication is an ``X-Nayax-Signature`` header: hex HMAC-SHA256 of the\nraw request body using the shared webhook secret. The terminal ID resolves\nwhich machine (and therefore which operator and which Nayax merchant\naccount) the transaction belongs to; the recorded order is force-routed to\nthat account regardless of what the payload claims.","operationId":"nayax_webhook_api_v1_payments_nayax_webhook_post","parameters":[{"name":"X-Nayax-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nayax-Signature"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","examples":[{"terminalId":"NYX903013700011","transactionId":"nyx_a1b2c3d4e5f60718","amount":5.99,"currency":"USD","method":"card","cardBrand":"visa","last4":"4242","authCode":"A1B2C3","aisleNo":1}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"orderNumber":"20260811000000000412","machineNo":"866903013700011","settlementAccountId":"nyx-act-63f2a9c01b","settlementAccountName":"Superior Vending Co."}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payments/nayax/spark/callback":{"post":{"tags":["Payments (Nayax)"],"summary":"Nayax Spark TransactionCallback (HMAC-signed)","description":"Endpoint Nayax calls when a Spark (remote-start) transaction is approved.\n\nUnlike the settlement webhook, this callback has a *physical* side effect:\non the Spark path nothing has told the machine anything yet, so approving\nhere is what pushes the MQTT dispense that drives the motors. It is\ntherefore signature-verified and fail-closed on its own secret, and\nidempotent on the Nayax transaction id — a replay books nothing twice and\nvends nothing twice.","operationId":"nayax_spark_callback_api_v1_payments_nayax_spark_callback_post","parameters":[{"name":"X-Nayax-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nayax-Signature"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","examples":[{"sparkTransactionId":"12c7cec2-c690-4425-9a1f-db0db60e2d8c","terminalId":"0434332923153297","transactionId":"nyx_spark_9f2c41","orderNumber":"K250817223001","amount":2.99,"currency":"USD","method":"card","cardBrand":"visa","last4":"4242","aisleNo":1}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payments":{"get":{"tags":["Payments (Nayax)"],"summary":"List Nayax payments","description":"Paginated card/wallet transactions with full acquiring detail.\n\nEvery record shows the terminal that took the tap, the card brand/last4,\nthe Nayax transaction ID, and the settlement account the money went to.\nEach record carries its ``settlementStatus`` (``settled``, ``pending``,\n``refunded``, ``voided``); device-reported sales stay ``pending`` — with no\ntransaction detail — until the Nayax webhook confirms them. Filter with\n``settlementStatus=settled`` for confirmed money only.\nCash sales are not listed here (no acquirer) — see the orders API.","operationId":"list_payments_api_v1_payments_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"settlementStatus","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Settlementstatus"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":20,"title":"Size"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"page":1,"size":20,"total":122,"records":[{"orderNumber":"20260809000000000345","machineNo":"866903013700011","buyTime":"2026-08-09T21:41:52.000+0000","productName":"Peak Protein","payStatus":"shipped","processor":"nayax","method":"card","terminalId":"NYX903013700011","deviceSerial":"VPOS29A81C64F1","transactionId":"nyx_9f2c1a7d3e5b0846","settlementAccountId":"nyx-act-63f2a9c01b","settlementAccountName":"Superior Vending Co.","cardBrand":"visa","last4":"4242","authCode":"A1B2C3","amount":4.99,"currency":"USD","settlementStatus":"settled"}]}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/rollouts":{"get":{"tags":["APK rollouts (OTA)"],"summary":"List rollouts","description":"All rollouts visible to your account, newest first, with live adoption\nstats (targeted / offered / upgraded / % complete).","operationId":"list_rollouts_api_v1_rollouts_get","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"rollouts":[{"rolloutId":"ro_4f2a9c1d8e7b","appId":"com.ruiye.jd","version":"1.0.43","apkUrl":"https://kiosk-x-docs.s3.us-east-1.amazonaws.com/downloads/reyeah-vending-kioskx.apk","apkSha256":"b1946ac92492d2347c6235b4d2611184a4e9b2c9f0f5b0f9a3c1d2e3f4a5b6c7","fileName":"reyeah-vending-kioskx.apk","notes":"Adds Nayax settlement display","strategy":{"percentage":50},"status":"active","operatorEmail":"admin@superiorvapevending.com","createdBy":"admin@superiorvapevending.com","createdAt":"2026-08-11T06:00:00.000+0000","adoption":{"targeted":2,"offered":1,"upgraded":1,"percentComplete":50.0},"machines":[{"machineNo":"866903013700011","machineName":"Ryan Test","currentVersion":"1.0.43","state":"upgraded","offeredAt":"2026-08-11T06:01:00.000+0000","upgradedAt":"2026-08-11T06:03:00.000+0000"},{"machineNo":"866903013700022","machineName":"Store Front","currentVersion":"1.0.42","state":"pending","offeredAt":null,"upgradedAt":null}]}]}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["APK rollouts (OTA)"],"summary":"Create an APK rollout","description":"Start offering a new APK build to your machines over the air.\n\nTargeted kiosks pick it up on their next `getUpgradeVersion` poll. Use\n`strategy.machines` for a canary on specific units, or\n`strategy.percentage` for a staged wave (bucketing is deterministic, so\n25% then 50% then 100% grows the same set — machines never flip waves).\n\nBy default the leading edge of the wave is also asked to check right away\n(`nudge`), so a canary is live in seconds rather than on the machines' own\nOTA interval. The nudge is bounded on purpose — see `app/ota.py`.","operationId":"create_rollout_api_v1_rollouts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RolloutCreateRequest"}}},"required":true},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"rolloutId":"ro_4f2a9c1d8e7b","appId":"com.ruiye.jd","version":"1.0.43","apkUrl":"https://kiosk-x-docs.s3.us-east-1.amazonaws.com/downloads/reyeah-vending-kioskx.apk","apkSha256":"b1946ac92492d2347c6235b4d2611184a4e9b2c9f0f5b0f9a3c1d2e3f4a5b6c7","fileName":"reyeah-vending-kioskx.apk","notes":"Adds Nayax settlement display","strategy":{"percentage":50},"status":"active","operatorEmail":"admin@superiorvapevending.com","createdBy":"admin@superiorvapevending.com","createdAt":"2026-08-11T06:00:00.000+0000","adoption":{"targeted":2,"offered":1,"upgraded":1,"percentComplete":50.0},"machines":[{"machineNo":"866903013700011","machineName":"Ryan Test","currentVersion":"1.0.43","state":"upgraded","offeredAt":"2026-08-11T06:01:00.000+0000","upgradedAt":"2026-08-11T06:03:00.000+0000"},{"machineNo":"866903013700022","machineName":"Store Front","currentVersion":"1.0.42","state":"pending","offeredAt":null,"upgradedAt":null}]}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/rollouts/{rolloutId}":{"get":{"tags":["APK rollouts (OTA)"],"summary":"Get rollout status","description":"Per-machine adoption detail: each targeted machine's current build and\nwhether it is pending, offered (poll seen), or upgraded (apkUp confirmed).","operationId":"get_rollout_api_v1_rollouts__rolloutId__get","parameters":[{"name":"rolloutId","in":"path","required":true,"schema":{"type":"string","title":"Rolloutid"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"rolloutId":"ro_4f2a9c1d8e7b","appId":"com.ruiye.jd","version":"1.0.43","apkUrl":"https://kiosk-x-docs.s3.us-east-1.amazonaws.com/downloads/reyeah-vending-kioskx.apk","apkSha256":"b1946ac92492d2347c6235b4d2611184a4e9b2c9f0f5b0f9a3c1d2e3f4a5b6c7","fileName":"reyeah-vending-kioskx.apk","notes":"Adds Nayax settlement display","strategy":{"percentage":50},"status":"active","operatorEmail":"admin@superiorvapevending.com","createdBy":"admin@superiorvapevending.com","createdAt":"2026-08-11T06:00:00.000+0000","adoption":{"targeted":2,"offered":1,"upgraded":1,"percentComplete":50.0},"machines":[{"machineNo":"866903013700011","machineName":"Ryan Test","currentVersion":"1.0.43","state":"upgraded","offeredAt":"2026-08-11T06:01:00.000+0000","upgradedAt":"2026-08-11T06:03:00.000+0000"},{"machineNo":"866903013700022","machineName":"Store Front","currentVersion":"1.0.42","state":"pending","offeredAt":null,"upgradedAt":null}]}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/rollouts/{rolloutId}/verify":{"post":{"tags":["APK rollouts (OTA)"],"summary":"Re-prove a rollout's artifact now","description":"Re-read the artifact and re-check it against everything this wave claims.\n\nThe background sweep does this on a timer, which is the right default but\nthe wrong tool twice: after replacing the bytes at a mutable path an\noperator needs to know *now* whether the wave is deliverable again, and\nwhile diagnosing a wave that is reaching nobody they need the verdict rather\nthan the fifteen minutes until the next sweep. Waiting is also how a\n\"verified\" badge ends up describing an artifact from a quarter of an hour\nago.\n\nErrors are returned rather than raised. The question being asked is \"what is\nwrong with this wave\", and a 500 answers it with the one thing an operator\ncannot act on.","operationId":"verify_rollout_api_v1_rollouts__rolloutId__verify_post","parameters":[{"name":"rolloutId","in":"path","required":true,"schema":{"type":"string","title":"Rolloutid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/rollouts/{rolloutId}/pause":{"post":{"tags":["APK rollouts (OTA)"],"summary":"Pause a rollout","description":"Stop offering the build (already-upgraded machines keep it).","operationId":"pause_rollout_api_v1_rollouts__rolloutId__pause_post","parameters":[{"name":"rolloutId","in":"path","required":true,"schema":{"type":"string","title":"Rolloutid"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"rolloutId":"ro_4f2a9c1d8e7b","appId":"com.ruiye.jd","version":"1.0.43","apkUrl":"https://kiosk-x-docs.s3.us-east-1.amazonaws.com/downloads/reyeah-vending-kioskx.apk","apkSha256":"b1946ac92492d2347c6235b4d2611184a4e9b2c9f0f5b0f9a3c1d2e3f4a5b6c7","fileName":"reyeah-vending-kioskx.apk","notes":"Adds Nayax settlement display","strategy":{"percentage":50},"status":"paused","operatorEmail":"admin@superiorvapevending.com","createdBy":"admin@superiorvapevending.com","createdAt":"2026-08-11T06:00:00.000+0000","adoption":{"targeted":2,"offered":1,"upgraded":1,"percentComplete":50.0},"machines":[{"machineNo":"866903013700011","machineName":"Ryan Test","currentVersion":"1.0.43","state":"upgraded","offeredAt":"2026-08-11T06:01:00.000+0000","upgradedAt":"2026-08-11T06:03:00.000+0000"},{"machineNo":"866903013700022","machineName":"Store Front","currentVersion":"1.0.42","state":"pending","offeredAt":null,"upgradedAt":null}]}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/rollouts/{rolloutId}/resume":{"post":{"tags":["APK rollouts (OTA)"],"summary":"Resume a paused rollout","description":"Start offering the build again to the remaining machines.\n\nResuming re-nudges the leading edge (bounded, as on create) — a pause that\nlasted longer than the machines' check interval otherwise leaves them\nwaiting out a full interval before they notice the wave is live again.","operationId":"resume_rollout_api_v1_rollouts__rolloutId__resume_post","parameters":[{"name":"rolloutId","in":"path","required":true,"schema":{"type":"string","title":"Rolloutid"}},{"name":"nudge","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Nudge"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"rolloutId":"ro_4f2a9c1d8e7b","appId":"com.ruiye.jd","version":"1.0.43","apkUrl":"https://kiosk-x-docs.s3.us-east-1.amazonaws.com/downloads/reyeah-vending-kioskx.apk","apkSha256":"b1946ac92492d2347c6235b4d2611184a4e9b2c9f0f5b0f9a3c1d2e3f4a5b6c7","fileName":"reyeah-vending-kioskx.apk","notes":"Adds Nayax settlement display","strategy":{"percentage":50},"status":"active","operatorEmail":"admin@superiorvapevending.com","createdBy":"admin@superiorvapevending.com","createdAt":"2026-08-11T06:00:00.000+0000","adoption":{"targeted":2,"offered":1,"upgraded":1,"percentComplete":50.0},"machines":[{"machineNo":"866903013700011","machineName":"Ryan Test","currentVersion":"1.0.43","state":"upgraded","offeredAt":"2026-08-11T06:01:00.000+0000","upgradedAt":"2026-08-11T06:03:00.000+0000"},{"machineNo":"866903013700022","machineName":"Store Front","currentVersion":"1.0.42","state":"pending","offeredAt":null,"upgradedAt":null}]}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/rollouts/{rolloutId}/cancel":{"post":{"tags":["APK rollouts (OTA)"],"summary":"Cancel a rollout","description":"Permanently withdraw the offer. Terminal — cannot be resumed.","operationId":"cancel_rollout_api_v1_rollouts__rolloutId__cancel_post","parameters":[{"name":"rolloutId","in":"path","required":true,"schema":{"type":"string","title":"Rolloutid"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"rolloutId":"ro_4f2a9c1d8e7b","appId":"com.ruiye.jd","version":"1.0.43","apkUrl":"https://kiosk-x-docs.s3.us-east-1.amazonaws.com/downloads/reyeah-vending-kioskx.apk","apkSha256":"b1946ac92492d2347c6235b4d2611184a4e9b2c9f0f5b0f9a3c1d2e3f4a5b6c7","fileName":"reyeah-vending-kioskx.apk","notes":"Adds Nayax settlement display","strategy":{"percentage":50},"status":"cancelled","operatorEmail":"admin@superiorvapevending.com","createdBy":"admin@superiorvapevending.com","createdAt":"2026-08-11T06:00:00.000+0000","adoption":{"targeted":2,"offered":1,"upgraded":1,"percentComplete":50.0},"machines":[{"machineNo":"866903013700011","machineName":"Ryan Test","currentVersion":"1.0.43","state":"upgraded","offeredAt":"2026-08-11T06:01:00.000+0000","upgradedAt":"2026-08-11T06:03:00.000+0000"},{"machineNo":"866903013700022","machineName":"Store Front","currentVersion":"1.0.42","state":"pending","offeredAt":null,"upgradedAt":null}]}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"404":{"description":"Resource not found (or owned by another operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":404,"message":"Machine not found","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions":{"get":{"tags":["Subscriptions"],"summary":"List subscriptions","description":"Paginated subscription list with the portal's three search filters.","operationId":"list_subscriptions_api_v1_subscriptions_get","parameters":[{"name":"subscriptionId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter: Subscription ID contains","title":"Subscriptionid"},"description":"Filter: Subscription ID contains"},{"name":"machineName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter: any device name contains","title":"Machinename"},"description":"Filter: any device name contains"},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter: any device number contains","title":"Machineno"},"description":"Filter: any device number contains"},{"name":"subscriptionStatus","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Active | On Trial | Cancelled","title":"Subscriptionstatus"},"description":"Active | On Trial | Cancelled"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":10,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Subscriptions"],"summary":"Subscribe devices","description":"Put one or more devices on a plan — the 'Subscribe' action.","operationId":"subscribe_api_v1_subscriptions_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__subscriptions__SubscribeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/pricing":{"get":{"tags":["Subscriptions"],"summary":"Get published plan pricing","description":"Published device-plan pricing — what a device costs BEFORE subscribing.\n\nPublic (no authentication) so pricing can be shown on login/marketing\nsurfaces as well as inside the console. Values are the same constants the\nbilling engine applies, so the advertised rate always matches the invoice.","operationId":"get_pricing_api_v1_subscriptions_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/{subscriptionId}":{"get":{"tags":["Subscriptions"],"summary":"Get subscription detail","description":"One subscription, including the full device list.","operationId":"get_subscription_api_v1_subscriptions__subscriptionId__get","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/{subscriptionId}/devices":{"get":{"tags":["Subscriptions"],"summary":"List subscription devices","description":"The devices covered by a subscription — the 'View' action in the table.","operationId":"list_devices_api_v1_subscriptions__subscriptionId__devices_get","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/{subscriptionId}/cancel":{"post":{"tags":["Subscriptions"],"summary":"Cancel a subscription","description":"Cancel a subscription (Manage Subscriptions). A Stripe-billed plan is\ncancelled at period end on the Stripe side too (paid-through honored).","operationId":"cancel_api_v1_subscriptions__subscriptionId__cancel_post","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/{subscriptionId}/machines/{machineNo}/protection-plan":{"get":{"tags":["Subscriptions"],"summary":"Get a machine's protection-plan state (alias)","description":"Plan state. While a signature is pending this also POLLS Documenso —\nthe fallback path when the webhook is unreachable — so the state the\noperator sees is never staler than one page refresh. A signed-but-not-\nyet-archived plan re-attempts S3 archival here too.","operationId":"get_insurance_api_v1_subscriptions__subscriptionId__machines__machineNo__protection_plan_get","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}},{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Subscriptions"],"summary":"Add the Machine Protection Plan (+$20/mo) — alias","description":"Create the Machine Protection Plan agreement from the Documenso\ntemplate (Plan Schedule pre-filled with the exact plan economics), send\nit for signature, and return the in-app signing URL. Gates, in order:\n\n1. ESIGN/UETA consent — the request must carry the operator's\n   affirmative acceptance of the electronic-records disclosure\n   (``esignConsent: true``); refused with 428 otherwise. The consent\n   record (disclosure version, timestamp, IP, user agent, signer\n   name/title) is stored with the envelope state.\n2. Signature — the $20/mo line only starts AFTER the document is signed.","operationId":"add_insurance_api_v1_subscriptions__subscriptionId__machines__machineNo__protection_plan_post","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}},{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ProtectionPlanRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/{subscriptionId}/machines/{machineNo}/insurance":{"get":{"tags":["Subscriptions"],"summary":"Get a machine's protection-plan state","description":"Plan state. While a signature is pending this also POLLS Documenso —\nthe fallback path when the webhook is unreachable — so the state the\noperator sees is never staler than one page refresh. A signed-but-not-\nyet-archived plan re-attempts S3 archival here too.","operationId":"get_insurance_api_v1_subscriptions__subscriptionId__machines__machineNo__insurance_get","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}},{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Subscriptions"],"summary":"Add the Machine Protection Plan (+$20/mo) — starts the eSignature flow","description":"Create the Machine Protection Plan agreement from the Documenso\ntemplate (Plan Schedule pre-filled with the exact plan economics), send\nit for signature, and return the in-app signing URL. Gates, in order:\n\n1. ESIGN/UETA consent — the request must carry the operator's\n   affirmative acceptance of the electronic-records disclosure\n   (``esignConsent: true``); refused with 428 otherwise. The consent\n   record (disclosure version, timestamp, IP, user agent, signer\n   name/title) is stored with the envelope state.\n2. Signature — the $20/mo line only starts AFTER the document is signed.","operationId":"add_insurance_api_v1_subscriptions__subscriptionId__machines__machineNo__insurance_post","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}},{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ProtectionPlanRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/{subscriptionId}/machines/{machineNo}/protection-plan/cancel":{"post":{"tags":["Subscriptions"],"summary":"Cancel a machine's protection plan (alias)","operationId":"cancel_insurance_api_v1_subscriptions__subscriptionId__machines__machineNo__protection_plan_cancel_post","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}},{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/{subscriptionId}/machines/{machineNo}/insurance/cancel":{"post":{"tags":["Subscriptions"],"summary":"Cancel a machine's protection plan","operationId":"cancel_insurance_api_v1_subscriptions__subscriptionId__machines__machineNo__insurance_cancel_post","parameters":[{"name":"subscriptionId","in":"path","required":true,"schema":{"type":"string","title":"Subscriptionid"}},{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/webhooks/esign":{"post":{"tags":["Subscriptions"],"summary":"Documenso webhook (contract signatures)","description":"Signature completion. Verified by the shared webhook secret; idempotent\non the Documenso event/document id (duplicate deliveries are no-ops).\n\nThe Documenso webhook is team-wide, so completions for EVERY platform\ncontract land here: protection-plan documents flip their plan active\n(and archive), and DFY placement-license documents (externalId\n``kioskx-dfy-{dealId}``) get their signed PDF + audit log archived to S3\nkeyed by deal id — the DFY flow's own webhook handles its stage\ntransitions independently.","operationId":"esign_webhook_api_v1_subscriptions_webhooks_esign_post","parameters":[{"name":"x-documenso-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Documenso-Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/webhooks/revenuecat":{"post":{"tags":["Subscriptions"],"summary":"RevenueCat lifecycle webhook","description":"Subscription lifecycle from RevenueCat (the Quizverse contract: static\nAuthorization header, constant-time compare; sandbox events allowed —\nthis whole rail runs Stripe TEST mode). Idempotent on RC event id.","operationId":"revenuecat_webhook_api_v1_subscriptions_webhooks_revenuecat_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/subscriptions/webhooks/stripe":{"post":{"tags":["Subscriptions"],"summary":"Stripe subscription webhook","description":"Stripe → kiosk-x subscription state. Signature-verified; idempotent\n(state transitions are absolute, re-deliveries converge). Also pushes the\nsubscription into RevenueCat (receipts sync) whenever it changes.","operationId":"stripe_subscription_webhook_api_v1_subscriptions_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/billing/account":{"get":{"tags":["Billing"],"summary":"Account information (service wallet)","description":"Wallet rows: available / frozen amount, credit, cumulative totals.","operationId":"account_information_api_v1_billing_account_get","parameters":[{"name":"userAccount","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter: user account contains","title":"Useraccount"},"description":"Filter: user account contains"},{"name":"userName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter: user name contains","title":"Username"},"description":"Filter: user name contains"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/billing/recharges":{"get":{"tags":["Billing"],"summary":"Recharge record","description":"Wallet top-ups and $0 service enrolments, newest first.","operationId":"recharge_record_api_v1_billing_recharges_get","parameters":[{"name":"startTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"}},{"name":"endTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime"}},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"serviceType","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"e.g. 'mail serve'","title":"Servicetype"},"description":"e.g. 'mail serve'"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/billing/recharges/export":{"get":{"tags":["Billing"],"summary":"Recharge record CSV export","operationId":"recharge_export_api_v1_billing_recharges_export_get","parameters":[{"name":"startTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"}},{"name":"endTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime"}},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"serviceType","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Servicetype"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/billing/details":{"get":{"tags":["Billing"],"summary":"Billing detail","description":"Per-order service billing lines with a filtered summation.","operationId":"billing_detail_api_v1_billing_details_get","parameters":[{"name":"userAccount","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Useraccount"}},{"name":"userName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"}},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"typeOfBill","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Normal","title":"Typeofbill"},"description":"Normal"},{"name":"serviceType","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"device plan | mail serve","title":"Servicetype"},"description":"device plan | mail serve"},{"name":"startTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"}},{"name":"endTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/billing/details/export":{"get":{"tags":["Billing"],"summary":"Billing detail CSV export","operationId":"billing_export_api_v1_billing_details_export_get","parameters":[{"name":"userAccount","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Useraccount"}},{"name":"userName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"}},{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"typeOfBill","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Typeofbill"}},{"name":"serviceType","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Servicetype"}},{"name":"startTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"}},{"name":"endTime","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/billing/renewals":{"get":{"tags":["Billing"],"summary":"Per-device renewal rows for a subscription","description":"The Renew Equipment modal: device, expiration date, renewal state.","operationId":"renewals_api_v1_billing_renewals_get","parameters":[{"name":"subscriptionId","in":"query","required":true,"schema":{"type":"string","title":"Subscriptionid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/billing/portal-link":{"get":{"tags":["Billing"],"summary":"Mint a signed billing-portal link","description":"Short-lived signed URL to the hosted billing portal for this operator.","operationId":"portal_link_api_v1_billing_portal_link_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/support/tickets":{"get":{"tags":["Support"],"summary":"List my support tickets","operationId":"list_tickets_api_v1_support_tickets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Support"],"summary":"Open a support ticket","operationId":"create_ticket_api_v1_support_tickets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/support/tickets/{ticketId}":{"get":{"tags":["Support"],"summary":"Ticket detail with message thread","operationId":"ticket_detail_api_v1_support_tickets__ticketId__get","parameters":[{"name":"ticketId","in":"path","required":true,"schema":{"type":"string","title":"Ticketid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/support/tickets/{ticketId}/messages":{"post":{"tags":["Support"],"summary":"Reply on a ticket","operationId":"ticket_reply_api_v1_support_tickets__ticketId__messages_post","parameters":[{"name":"ticketId","in":"path","required":true,"schema":{"type":"string","title":"Ticketid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketReply"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/support/help":{"get":{"tags":["Support"],"summary":"Help collections","description":"Public help library (no auth needed so the login page can link it).","operationId":"help_collections_api_v1_support_help_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search articles","title":"Q"},"description":"Search articles"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/support/tasks":{"get":{"tags":["Support"],"summary":"Onboarding checklist (derived from real state)","operationId":"tasks_api_v1_support_tasks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/support/tasks/{taskId}/complete":{"post":{"tags":["Support"],"summary":"Mark a manual task done","operationId":"complete_task_api_v1_support_tasks__taskId__complete_post","parameters":[{"name":"taskId","in":"path","required":true,"schema":{"type":"string","title":"Taskid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/support/app-qr":{"get":{"tags":["Support"],"summary":"Operator app download QR (PNG)","description":"Kiosk-X-branded QR encoding the operator app download for the\nrequested platform. Public: it renders inside the setup checklist\nbefore sign-in too.","operationId":"app_qr_api_v1_support_app_qr_get","parameters":[{"name":"platform","in":"query","required":false,"schema":{"type":"string","pattern":"^(ios|android)$","default":"android","title":"Platform"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":1024,"minimum":240,"default":480,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/auth/change-password":{"post":{"tags":["Auth"],"summary":"Change my console password","description":"Verify the old password, validate and set the new one.","operationId":"change_password_api_v1_auth_change_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/pricing":{"get":{"tags":["Pricing"],"summary":"Get the full pricing catalog (public)","description":"The canonical, machine-readable pricing catalog for every QR use case.\n\nAmounts are integer **cents, USD**. Each value is marked ``source: live``\n(read from the module that bills it) or ``source: recommended`` (the\nconvergence target for in-flight flows). No authentication required.","operationId":"get_pricing_catalog_api_v1_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns":{"post":{"tags":["Ads & sponsorships"],"summary":"Create a sponsorship campaign","description":"Create a direct-sold flight for your kiosk ad loop (starts as `draft`).\n\n`weight` is the number of slots per loop rotation the sponsor bought\n(loops run 8 x 15s by default). Activate it once the creative is set and\nevery targeted kiosk picks it up on its next `getAd` poll.","operationId":"create_campaign_api_v1_campaigns_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignCreateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"get":{"tags":["Ads & sponsorships"],"summary":"List campaigns","description":"Your sponsorship campaigns, newest first, paginated.","operationId":"list_campaigns_api_v1_campaigns_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"draft | active | paused | completed","title":"Status"},"description":"draft | active | paused | completed"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/reports/summary":{"get":{"tags":["Ads & sponsorships"],"summary":"Fleet ad revenue summary","description":"Every campaign's plays/impressions/revenue plus the loop-wide split of\ndirect-sold vs programmatic vs house plays — the money view of the loop.","operationId":"campaigns_summary_api_v1_campaigns_reports_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/reports/machines/{machineNo}":{"get":{"tags":["Ads & sponsorships"],"summary":"One machine's screen: what it played, what it earned, what is in its loop now","description":"The per-cabinet answer to \"what is my screen doing\": plays by source\n(all-time and last 24h), est. revenue, the creatives that actually ran on\nthis machine ranked by plays, and the loop the cabinet is being served\nright now (same assembly as ``/apk/getAd`` / ``/kiosk/api/ads``).","operationId":"machine_screen_report_api_v1_campaigns_reports_machines__machineNo__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/{campaignId}":{"get":{"tags":["Ads & sponsorships"],"summary":"Get a campaign","operationId":"get_campaign_api_v1_campaigns__campaignId__get","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Ads & sponsorships"],"summary":"Update a campaign","operationId":"update_campaign_api_v1_campaigns__campaignId__put","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"delete":{"tags":["Ads & sponsorships"],"summary":"Delete a draft campaign","operationId":"delete_campaign_api_v1_campaigns__campaignId__delete","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/{campaignId}/activate":{"post":{"tags":["Ads & sponsorships"],"summary":"Activate a campaign","description":"Start the flight: targeted kiosks add it to their loop on the next\n`getAd` poll. Requires a creative.","operationId":"activate_campaign_api_v1_campaigns__campaignId__activate_post","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/{campaignId}/pause":{"post":{"tags":["Ads & sponsorships"],"summary":"Pause a campaign","operationId":"pause_campaign_api_v1_campaigns__campaignId__pause_post","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/{campaignId}/complete":{"post":{"tags":["Ads & sponsorships"],"summary":"Complete a campaign","operationId":"complete_campaign_api_v1_campaigns__campaignId__complete_post","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/{campaignId}/report":{"get":{"tags":["Ads & sponsorships"],"summary":"Campaign performance report","description":"Proof-of-play-backed sponsor report: plays, estimated impressions\n(plays x each venue's impressions-per-play), and estimated revenue\n(prorated flat monthly or CPM x impressions).","operationId":"campaign_report_api_v1_campaigns__campaignId__report_get","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/{campaignId}/creative/contentx":{"post":{"tags":["Ads & sponsorships"],"summary":"Generate the creative via ContentX","description":"Brief → ContentX AI Studio generation → hosted asset URL → campaign\ncreative, in one call.\n\nForwards the brief to ContentX (`POST {CONTENTX_API_BASE}/ai-studio/\ntext-to-image`), which generates the asset and hosts it (S3); the returned\nURL is attached to this campaign with `creativeSource: contentx`. If the\nContentX GPU fleet is down the upstream error is returned verbatim as a\n502 — nothing is faked.","operationId":"contentx_creative_api_v1_campaigns__campaignId__creative_contentx_post","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentxCreativeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/campaigns/{campaignId}/creative/upload":{"post":{"tags":["Ads & sponsorships"],"summary":"Upload the creative (portrait PNG/JPEG/WebP poster or MP4 clip) and attach it","description":"The third way to give a campaign its creative, next to pasting a URL\nand generating one with ContentX: send the file itself.\n\nThe file is checked the way a self-serve advertiser's is (``adflow.\nvalidate_upload`` — type, size, portrait, ≥540x960; MP4 must fit the loop\nslot), hosted, and attached with ``source: upload``. The campaign stays in\nwhatever status it was; a draft becomes activatable because it now has a\ncreative URL. Nothing about the flight, targets or pricing changes.","operationId":"upload_creative_api_v1_campaigns__campaignId__creative_upload_post","parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string","title":"Campaignid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreativeUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dooh/inventory":{"get":{"tags":["Ads & sponsorships"],"summary":"DOOH inventory export (SSP onboarding)","description":"Every machine's screen as a DOOH inventory unit — venue name/geo,\nOpenOOH Venue Taxonomy category, panel size/resolution, loop shape, and\nimpressions-per-play — shaped for Vistar Media / Place Exchange screen\nsubmission.","operationId":"dooh_inventory_api_v1_dooh_inventory_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dooh/proof-of-play":{"get":{"tags":["Ads & sponsorships"],"summary":"Proof-of-play export","description":"The play ledger (one row per creative per machine per showing) that\nbacks sponsor reports and the SSP proof-of-play feed.","operationId":"proof_of_play_export_api_v1_dooh_proof_of_play_get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"campaignId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaignid"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"direct | programmatic | house","title":"Source"},"description":"direct | programmatic | house"},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO timestamp lower bound","title":"Since"},"description":"ISO timestamp lower bound"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/mediation/adapters":{"get":{"tags":["Ad mediation"],"summary":"Attached demand sources and their modes","operationId":"list_adapters_api_v1_mediation_adapters_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/mediation/creatives":{"get":{"tags":["Ad mediation"],"summary":"Programmatic creative approval queue","operationId":"list_creatives_api_v1_mediation_creatives_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"pending | approved | rejected","title":"Status"},"description":"pending | approved | rejected"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/mediation/creatives/{creative_id}/approve":{"post":{"tags":["Ad mediation"],"summary":"Approve a programmatic creative","operationId":"approve_creative_api_v1_mediation_creatives__creative_id__approve_post","parameters":[{"name":"creative_id","in":"path","required":true,"schema":{"type":"string","title":"Creative Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/mediation/creatives/{creative_id}/reject":{"post":{"tags":["Ad mediation"],"summary":"Reject a programmatic creative","operationId":"reject_creative_api_v1_mediation_creatives__creative_id__reject_post","parameters":[{"name":"creative_id","in":"path","required":true,"schema":{"type":"string","title":"Creative Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/mediation/pop":{"get":{"tags":["Ad mediation"],"summary":"PoP receipts and the dispatch queue","operationId":"pop_state_api_v1_mediation_pop_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"pending | settled | expired","title":"Status"},"description":"pending | settled | expired"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/advertise-qr":{"get":{"tags":["Self-serve ad purchases"],"summary":"Personalized 'Advertise here' QR (PNG)","description":"ContentX-branded QR code (CX logo center, ContentX magenta modules —\nthe ad studio behind the scan is ContentX-powered) encoding this machine's\nself-serve ad purchase URL. Print it on/near the kiosk — the buyer chat\nopens pre-targeted to this machine and venue, and every purchase it\noriginates carries the QR's stable ``qrId`` for scan-to-revenue\nattribution (`format=json` returns the id + URL without the image).","operationId":"advertise_qr_api_v1_machines__machineNo__advertise_qr_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":1024,"minimum":240,"default":640,"title":"Size"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"png | json","default":"png","title":"Format"},"description":"png | json"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/ad-purchases":{"get":{"tags":["Self-serve ad purchases"],"summary":"List self-serve ad purchases","description":"Every self-serve purchase against your fleet, newest first —\n`pending_approval` is your approval queue.","operationId":"list_ad_purchases_api_v1_ad_purchases_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"collecting | awaiting_payment | pending_approval | live | rejected","title":"Status"},"description":"collecting | awaiting_payment | pending_approval | live | rejected"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/ad-purchases/{purchaseId}":{"get":{"tags":["Self-serve ad purchases"],"summary":"Get a self-serve ad purchase","operationId":"get_ad_purchase_api_v1_ad_purchases__purchaseId__get","parameters":[{"name":"purchaseId","in":"path","required":true,"schema":{"type":"string","title":"Purchaseid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/ad-purchases/{purchaseId}/approve":{"post":{"tags":["Self-serve ad purchases"],"summary":"Approve a paid ad purchase","description":"Activates the campaign — targeted kiosks pick it up on their next\n`getAd` poll and the buyer's status page flips to *live*.","operationId":"approve_ad_purchase_api_v1_ad_purchases__purchaseId__approve_post","parameters":[{"name":"purchaseId","in":"path","required":true,"schema":{"type":"string","title":"Purchaseid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/ad-purchases/{purchaseId}/reject":{"post":{"tags":["Self-serve ad purchases"],"summary":"Reject a paid ad purchase","description":"Records the reason (shown to the buyer on their status page). The\npayment is NOT auto-refunded — refund from the Stripe dashboard\n(Payments → the purchase's payment intent → Refund).","operationId":"reject_ad_purchase_api_v1_ad_purchases__purchaseId__reject_post","parameters":[{"name":"purchaseId","in":"path","required":true,"schema":{"type":"string","title":"Purchaseid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/assistant/chat":{"post":{"tags":["Operator assistant"],"summary":"One operator-assistant chat turn","description":"Ask a fleet question or give a command in plain language.\n\nThe assistant answers with LIVE data from this credential's own fleet and\ncan act: restock a machine, create/activate an ad campaign, email a sales\ndigest or low-stock report, set up offline/low-stock alert subscriptions,\nor place an AI voice call. Returns the reply plus structured ``actions``\nthe console renders (links, created entities, sent notifications).","operationId":"chat_api_v1_assistant_chat_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/assistant/capabilities":{"get":{"tags":["Operator assistant"],"summary":"What the assistant can do here","description":"Which tools this deployment/credential supports — the console uses it\nto show honest quick-action chips (no dead buttons: email/voice entries\nappear only when those engagement-stack services are configured).","operationId":"capabilities_api_v1_assistant_capabilities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/fleet/census":{"get":{"tags":["Machines"],"summary":"Which machine records are cabinets","description":"Real machines, gateway fixtures, and records nobody has heard from.\n\nThe fleet's machine table holds three kinds of row and every count built on\nit — rollout targets, adoption, tax coverage, health — used to treat them\nas one. This is the read that separates them, with the evidence behind each\nverdict attached so nothing has to be taken on trust. See app/census.py.","operationId":"fleet_census_api_v1_fleet_census_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/fleet/glance":{"get":{"tags":["Machines"],"summary":"Fleet at a glance (widget-friendly)","description":"Today's sales, machines online/total, and the low-stock aisle count —\neverything a home-screen widget shows, in one call.","operationId":"glance_api_v1_fleet_glance_get","parameters":[{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":840,"minimum":-840},{"type":"null"}],"description":"Client UTC offset (JS: -new Date().getTimezoneOffset())","title":"Tzoffsetminutes"},"description":"Client UTC offset (JS: -new Date().getTimezoneOffset())"},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone for the day buckets, e.g. Pacific/Auckland. Preferred over the offset, which cannot describe a day across a daylight-saving change.","title":"Timezone"},"description":"IANA zone for the day buckets, e.g. Pacific/Auckland. Preferred over the offset, which cannot describe a day across a daylight-saving change."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/fleet/protection":{"get":{"tags":["Machines"],"summary":"Fleet protection-plan coverage summary + popup decision","description":"Coverage counts, uncovered machine numbers, one-tap enrollment targets,\nplan pricing, and — for operator principals — the server-side ``nudge``\ndecision (show the popup now or not, and why).\n\nClients poll this (60–90 s is plenty); the poll itself feeds the\nsession clock the first-nudge delay hangs off. Admin keys get the\nplatform-wide summary — or one operator's, with ``?operatorEmail=`` —\nwith the nudge disabled (the popup is a per-operator conversion surface,\nnot an admin one).","operationId":"protection_summary_api_v1_fleet_protection_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/fleet/protection/nudge":{"post":{"tags":["Machines"],"summary":"Record a protection-plan popup event","description":"The client reports what happened to the popup: ``shown`` (displayed —\nstarts the frequency cooldown), ``snooze`` (\"Remind me later\"), or\n``dismiss`` (\"No thanks\" — three of these stop the popup permanently).\nRequires only machines:read — this is per-operator UI preference state,\nnot a fleet mutation.","operationId":"nudge_action_api_v1_fleet_protection_nudge_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NudgeActionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/protection-offer":{"get":{"tags":["Machines"],"summary":"The machine's protection-plan offer (inline step)","description":"What the delivery / installation-completion surfaces render inline:\nthe open offer (if the lifecycle trigger fired), the machine's coverage\nstate, plan economics, and how enrollment would attach (the live base\nsubscription, or ``basePlan.required`` when accepting must start one).\nRequires machines:read.","operationId":"get_protection_offer_api_v1_machines__machineNo__protection_offer_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/protection-offer/accept":{"post":{"tags":["Machines"],"summary":"Accept the offer — starts the eSignature flow","description":"Approve the Machine Protection Plan at the delivery/install moment.\nSends the machine-specific agreement (serial, model, operator, premium\npre-filled) through the existing Documenso rail and returns the signing\nURL; the machine's protection state is ``pending_signature`` until the\nsignature completes, then activation attaches the $20/mo line.\nRequires machines:write.","operationId":"accept_protection_offer_api_v1_machines__machineNo__protection_offer_accept_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/OfferAcceptRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/protection-offer/decline":{"post":{"tags":["Machines"],"summary":"Decline the offer (recorded; nudges take over)","description":"The plan is optional: declining is always allowed, is timestamped on\nthe offer and the machine's lifecycle timeline, keeps the uninsured\nbadge, and hands conversion back to the existing nudge policy.\nRequires machines:write.","operationId":"decline_protection_offer_api_v1_machines__machineNo__protection_offer_decline_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/OfferDeclineRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/subscription":{"get":{"tags":["Operator Reads"],"summary":"Get Operator Reads activation status","operationId":"get_subscription_api_v1_operator_reads_subscription_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Admin only: act on this operator","title":"Operatoremail"},"description":"Admin only: act on this operator"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator Reads"],"summary":"Activate Operator Reads for this operator","description":"Turns the agent ON for the caller's user-id: the scheduled n8n runs\ninclude this operator from now on, and the feed endpoints unlock.","operationId":"subscribe_api_v1_operator_reads_subscription_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_reads__SubscribeRequest","default":{}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/subscription/cancel":{"post":{"tags":["Operator Reads"],"summary":"Deactivate Operator Reads","description":"Turns the agent OFF. The shortlist is kept (and keeps its read/saved\nstate) so re-activating later doesn't start from a blank feed.","operationId":"unsubscribe_api_v1_operator_reads_subscription_cancel_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_reads__SubscribeRequest","default":{}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/profile":{"get":{"tags":["Operator Reads"],"summary":"Derived curation profile for this operator","description":"What the agent personalizes with — derived live from the fleet.","operationId":"get_profile_api_v1_operator_reads_profile_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/feed":{"get":{"tags":["Operator Reads"],"summary":"Personalized article shortlist","description":"Newest-and-most-relevant first. Every item carries its relevance\nreasons (e.g. \"matches your 'alcohol' vertical\", \"near your Airport T2\nmachine\") so the ranking is explainable in the UI.","operationId":"get_feed_api_v1_operator_reads_feed_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"view","in":"query","required":false,"schema":{"type":"string","description":"inbox (new+read) | saved | dismissed | all","default":"inbox","title":"View"},"description":"inbox (new+read) | saved | dismissed | all"},{"name":"unreadOnly","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Unreadonly"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/feed/{itemId}/{action}":{"post":{"tags":["Operator Reads"],"summary":"Mark an item read / saved / dismissed","operationId":"item_action_api_v1_operator_reads_feed__itemId___action__post","parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","title":"Itemid"}},{"name":"action","in":"path","required":true,"schema":{"type":"string","title":"Action"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/refresh":{"post":{"tags":["Operator Reads"],"summary":"Trigger a curation run for this operator now","description":"Pull-to-refresh: asks the n8n workflow to re-curate this operator\nimmediately (the scheduled run covers everyone periodically). Cooldown-\nlimited — every run spends real Firecrawl credits.","operationId":"refresh_api_v1_operator_reads_refresh_post","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/subscribers":{"get":{"tags":["Operator Reads"],"summary":"Active subscribers + profiles (curation workflow)","description":"What the scheduled n8n run iterates: every active subscriber with the\nfleet-derived profile to personalize their queries. Fleet-admin only.","operationId":"subscribers_api_v1_operator_reads_subscribers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-reads/ingest":{"post":{"tags":["Operator Reads"],"summary":"Curation callback — store a shortlist batch","description":"The n8n workflow's authenticated write-back. Non-admin callers can\nonly ingest into their OWN feed; the target operator must have the agent\nactive. baseScore is recomputed server-side from the relevance evidence.","operationId":"ingest_api_v1_operator_reads_ingest_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/keywords":{"get":{"tags":["Location Scout"],"summary":"Keyword verticals the scout can research","description":"The extensible vertical registry: label, top predictive venues, base\nrevenue anchor, and — for age-restricted verticals (vape, alcohol) — the\ncompliance notes the app must surface prominently.","operationId":"keywords_api_v1_location_scout_keywords_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/subscription":{"get":{"tags":["Location Scout"],"summary":"My Location Scout subscription","operationId":"get_subscription_api_v1_location_scout_subscription_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Location Scout"],"summary":"Activate the Location Scout agent","description":"Activates the agent for THIS user-id (idempotent). In the sandbox the\nactivation is immediate; the RevenueCat in-app-purchase flow lands on the\nsame record via ``revenueCatRef``.","operationId":"subscribe_api_v1_location_scout_subscription_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeBody","default":{"source":"operator-x-app"}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/subscription/cancel":{"post":{"tags":["Location Scout"],"summary":"Cancel the Location Scout agent","operationId":"cancel_api_v1_location_scout_subscription_cancel_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/requests":{"post":{"tags":["Location Scout"],"summary":"Submit a scout request","description":"Free text and/or structured fields. The request is dispatched to the\nn8n Location Scout workflow; if n8n can't be reached the same research\nruns inline and the response is already completed. Requires an active\nsubscription (402 otherwise).","operationId":"submit_api_v1_location_scout_requests_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScoutRequestBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"get":{"tags":["Location Scout"],"summary":"My scout request history","operationId":"list_requests_api_v1_location_scout_requests_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/requests/{request_id}":{"get":{"tags":["Location Scout"],"summary":"Scout request status + results","description":"Poll for status/results. A request stuck in flight past the stale\nwindow (n8n accepted the dispatch and died, pod restarted mid-research)\nis re-run locally by this replica — polling always converges.","operationId":"get_request_api_v1_location_scout_requests__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/requests/{request_id}/outreach":{"post":{"tags":["Location Scout"],"summary":"Start DFY outreach on a scouted candidate (one tap)","description":"The Scout → Outreach bridge: lands one scouted location on a DFY deal\nas a placement candidate (business contact prefilled when the enrichment\nCITED a real email/phone; `needs_contact` otherwise), approves it, and\narms the sequenced outreach — the confirm flag on this call IS the\noperator's batch approval gate. All downstream guardrails (call window,\ndecline stop, negotiation envelope, lease/money checkpoints) apply\nunchanged.","operationId":"start_outreach_from_scout_api_v1_location_scout_requests__request_id__outreach_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScoutOutreachBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/research":{"post":{"tags":["Location Scout"],"summary":"Run the research loop (n8n-facing)","description":"The research brain, callable by the n8n workflow: parses the query (if\nstill unparsed) and runs the loop-engineered candidate search, returning\nranked results + the evidence summary. The self-hosted geo stack\n(Photon POI search) and LiteLLM credentials stay server-side.","operationId":"research_api_v1_location_scout_research_post","parameters":[{"name":"x-scout-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Scout-Token"}},{"name":"x-scout-signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Scout-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/location-scout/callback/{request_id}":{"post":{"tags":["Location Scout"],"summary":"Result ingest (n8n-facing)","description":"Stores the workflow's results on the request. Idempotent: the first\ncompletion wins; duplicate callbacks are acknowledged with\n``applied: false``. Malformed payloads are a 400.","operationId":"callback_api_v1_location_scout_callback__request_id__post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}},{"name":"x-scout-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Scout-Token"}},{"name":"x-scout-signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Scout-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/catalog":{"get":{"tags":["DFY Vending"],"summary":"HotBox machine catalog (3 models)","description":"Public read: models, prices, specs — server-side truth the checkout\ncharges from (the client can never set a price).","operationId":"catalog_api_v1_dfy_catalog_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/fleets":{"get":{"tags":["DFY Vending"],"summary":"Fleet pool + investments","operationId":"fleet_pool_api_v1_dfy_fleets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["DFY Vending"],"summary":"Launch a fleet (whole machines and/or invest any amount)","operationId":"launch_fleet_api_v1_dfy_fleets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LaunchFleetRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/investments/{invId}/poll":{"post":{"tags":["DFY Vending"],"summary":"Reconcile an investment payment","operationId":"poll_investment_api_v1_dfy_investments__invId__poll_post","parameters":[{"name":"invId","in":"path","required":true,"schema":{"type":"string","title":"Invid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/investments/{invId}/simulate":{"get":{"tags":["DFY Vending"],"summary":"Simulated investment checkout completion (sandbox only)","description":"Completes a SIMULATED investment checkout (only exists when Stripe is\nnot configured on the deployment — clearly labelled, token-guarded).","operationId":"simulate_investment_api_v1_dfy_investments__invId__simulate_get","parameters":[{"name":"invId","in":"path","required":true,"schema":{"type":"string","title":"Invid"}},{"name":"tok","in":"query","required":true,"schema":{"type":"string","title":"Tok"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals":{"get":{"tags":["DFY Vending"],"summary":"List deals","operationId":"list_deals_api_v1_dfy_deals_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["DFY Vending"],"summary":"Open a DFY deal","operationId":"create_deal_api_v1_dfy_deals_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDealRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/board":{"get":{"tags":["DFY Vending"],"summary":"Pipeline board (kanban)","operationId":"board_api_v1_dfy_board_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}":{"get":{"tags":["DFY Vending"],"summary":"Deal detail","description":"Detail read — also the pipeline's lazy heartbeat: due outreach touches\nrun, Documenso poll fallback runs while a signature is out, and the\nautopilot advances whatever autonomy allows.","operationId":"deal_detail_api_v1_dfy_deals__dealId__get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/cancel":{"post":{"tags":["DFY Vending"],"summary":"Cancel a deal","operationId":"cancel_deal_api_v1_dfy_deals__dealId__cancel_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/shortlist":{"post":{"tags":["DFY Vending"],"summary":"Start the Location Scout shortlist","operationId":"start_shortlist_api_v1_dfy_deals__dealId__shortlist_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShortlistRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/shortlist/refresh":{"post":{"tags":["DFY Vending"],"summary":"Poll scout results","operationId":"refresh_shortlist_api_v1_dfy_deals__dealId__shortlist_refresh_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/candidates/approve":{"post":{"tags":["DFY Vending"],"summary":"Approve shortlist candidates","operationId":"approve_candidates_api_v1_dfy_deals__dealId__candidates_approve_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveCandidatesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/candidates/{candidateId}/contact":{"put":{"tags":["DFY Vending"],"summary":"Set a candidate's contact","operationId":"set_contact_api_v1_dfy_deals__dealId__candidates__candidateId__contact_put","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}},{"name":"candidateId","in":"path","required":true,"schema":{"type":"string","title":"Candidateid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/outreach/start":{"post":{"tags":["DFY Vending"],"summary":"Arm sequenced outreach (confirm gate)","operationId":"outreach_start_api_v1_dfy_deals__dealId__outreach_start_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutreachStartRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/outreach/tick":{"post":{"tags":["DFY Vending"],"summary":"Advance due outreach touches","operationId":"outreach_tick_api_v1_dfy_deals__dealId__outreach_tick_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/candidates/{candidateId}/outcome":{"post":{"tags":["DFY Vending"],"summary":"Record a call/email outcome","operationId":"record_outcome_api_v1_dfy_deals__dealId__candidates__candidateId__outcome_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}},{"name":"candidateId","in":"path","required":true,"schema":{"type":"string","title":"Candidateid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutcomeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/webhooks/inbound-email":{"post":{"tags":["DFY Vending"],"summary":"Inbound counterparty email (n8n Gmail bridge)","description":"The org inbox → deal pipeline seam. Authenticated by the shared secret\nminted in-cluster (kube-infra CI); 503 when not provisioned — the surface\nis never open by accident. Body: {from, subject, text, messageId?}.","operationId":"inbound_email_webhook_api_v1_dfy_webhooks_inbound_email_post","parameters":[{"name":"x-kx-inbound-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Kx-Inbound-Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/webhooks/voice-transcript":{"post":{"tags":["DFY Vending"],"summary":"Voice conversation transcript (Fonoster eventsHook via n8n VOICE.CallEnded)","description":"Closes the voice leg of the outreach loop: the Fonoster autopilot\nfires conversation.ended with the chat history, the n8n VOICE.CallEnded\nworkflow fans it out here, and the transcript auto-ingests through the\nsame extraction path as email. Same shared secret as inbound-email;\n503 when not provisioned. Body: {callRef, transcript?, chatHistory?,\nrecordingUrl?}.","operationId":"voice_transcript_webhook_api_v1_dfy_webhooks_voice_transcript_post","parameters":[{"name":"x-kx-inbound-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Kx-Inbound-Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/webhooks/inbound-sms":{"post":{"tags":["DFY Vending"],"summary":"Inbound counterparty SMS (Telnyx via n8n bridge)","description":"The SMS leg of the inbound loop: Telnyx ``message.received`` events\n(bridged through n8n, which adds the shared-secret header) land here and\nroute down the same extraction→negotiation path as email/voice, threaded\nby the sender's number. STOP is honored before anything else.\n\nThe ``secret`` query parameter is a **deprecated** second arm, kept only\nuntil it can be shown unused. Its stated justification — that Telnyx\nwebhooks cannot set custom headers — does not describe this route: Telnyx\ndoes not call it. The n8n ``SMS.Touch`` workflow does, over the in-cluster\nservice address, and it sets ``X-KX-Inbound-Secret``. A credential in a\nquery string is written verbatim into every access log that sees the\nrequest, so the arm is worth removing; it is still accepted here because\n\"no caller we know of\" is not the same as \"no caller\", and an SMS reply\nsilently 401ing is a lost counterparty conversation. The warning below is\nwhat turns the first into the second.","operationId":"inbound_sms_webhook_api_v1_dfy_webhooks_inbound_sms_post","parameters":[{"name":"secret","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secret"}},{"name":"x-kx-inbound-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Kx-Inbound-Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/outreach/preview":{"get":{"tags":["DFY Vending"],"summary":"Per-channel script preview (what the agent will say)","description":"Exactly what will go out on each channel for this candidate at the\nCURRENT stage — the send paths call the identical renderers, so the\npreview is the message. Includes per-channel availability so the console\ncan show why a channel won't fire (no phone, unconfigured, STOP).","operationId":"outreach_preview_api_v1_dfy_deals__dealId__outreach_preview_get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}},{"name":"candidateId","in":"query","required":true,"schema":{"type":"string","title":"Candidateid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/candidates/{candidateId}/call/refresh":{"post":{"tags":["DFY Vending"],"summary":"Refresh the Fonoster call detail","operationId":"refresh_call_api_v1_dfy_deals__dealId__candidates__candidateId__call_refresh_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}},{"name":"candidateId","in":"path","required":true,"schema":{"type":"string","title":"Candidateid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/select":{"post":{"tags":["DFY Vending"],"summary":"Pick the winning site","operationId":"select_candidate_api_v1_dfy_deals__dealId__select_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/envelope":{"put":{"tags":["DFY Vending"],"summary":"Set the negotiation mandate","operationId":"set_envelope_api_v1_dfy_deals__dealId__negotiation_envelope_put","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvelopeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/start":{"post":{"tags":["DFY Vending"],"summary":"Start negotiating (checkpoint: operator approves the target)","operationId":"negotiation_start_api_v1_dfy_deals__dealId__negotiation_start_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NegotiationStartRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/counter":{"post":{"tags":["DFY Vending"],"summary":"Ingest a counterparty turn (voice transcript / email)","operationId":"negotiation_counter_api_v1_dfy_deals__dealId__negotiation_counter_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CounterRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/accept":{"post":{"tags":["DFY Vending"],"summary":"Counterparty accepts the standing offer","operationId":"negotiation_accept_api_v1_dfy_deals__dealId__negotiation_accept_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/approve-terms":{"post":{"tags":["DFY Vending"],"summary":"Approve edge/low-confidence negotiated terms (checkpoint)","operationId":"approve_terms_api_v1_dfy_deals__dealId__negotiation_approve_terms_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveTermsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/review":{"post":{"tags":["DFY Vending"],"summary":"Resolve an escalation","operationId":"resolve_review_api_v1_dfy_deals__dealId__negotiation_review_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/graph":{"get":{"tags":["DFY Vending"],"summary":"The deal's negotiation graph","operationId":"negotiation_graph_api_v1_dfy_deals__dealId__negotiation_graph_get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/negotiation/graphs":{"get":{"tags":["DFY Vending"],"summary":"Portfolio-wide negotiation analytics","description":"Cross-deal convergence patterns ('share converged at 14–16% in transit\nhubs vs 18–20% in nightlife') — the same data the agent's opening-offer\nlearning consults, so what the operator sees IS what the agent uses.","operationId":"negotiation_graphs_api_v1_dfy_negotiation_graphs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/lease/chat":{"post":{"tags":["DFY Vending"],"summary":"Refine lease terms conversationally","operationId":"lease_chat_api_v1_dfy_deals__dealId__lease_chat_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaseChatRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/lease/preview":{"get":{"tags":["DFY Vending"],"summary":"Live term-sheet preview","operationId":"lease_preview_api_v1_dfy_deals__dealId__lease_preview_get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/lease/send":{"post":{"tags":["DFY Vending"],"summary":"Send the placement agreement for eSignature (checkpoint)","operationId":"send_lease_api_v1_dfy_deals__dealId__lease_send_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendLeaseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/lease/poll":{"post":{"tags":["DFY Vending"],"summary":"Poll Documenso for signature state","operationId":"poll_lease_api_v1_dfy_deals__dealId__lease_poll_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/webhooks/esign":{"post":{"tags":["DFY Vending"],"summary":"Documenso webhook (placement agreements)","description":"Same contract as the insurance webhook: shared-secret verified,\nidempotent on the event/document id.","operationId":"esign_webhook_api_v1_dfy_webhooks_esign_post","parameters":[{"name":"x-documenso-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Documenso-Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/order/checkout":{"post":{"tags":["DFY Vending"],"summary":"Machine checkout (checkpoint: money)","operationId":"order_checkout_api_v1_dfy_deals__dealId__order_checkout_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/preorder":{"post":{"tags":["DFY Vending"],"summary":"Stage-0 pre-order: new deal + checkout in one step","description":"The pre-order entry point (Operator X app, web console, and the\nkiosk-x.ai site after operator signup): full price, one-time TEST-mode\npayment, refundable until shipped. Lands the deal in the pipeline at\n'pre_ordered'.","operationId":"preorder_api_v1_dfy_preorder_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreorderRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/order/poll":{"post":{"tags":["DFY Vending"],"summary":"Poll Stripe for the payment state","operationId":"poll_order_api_v1_dfy_deals__dealId__order_poll_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/order/simulate":{"get":{"tags":["DFY Vending"],"summary":"Simulated checkout completion (sandbox only)","description":"Completes a SIMULATED checkout (only exists when Stripe is not\nconfigured on the deployment — clearly labelled, token-guarded).","operationId":"simulate_order_api_v1_dfy_deals__dealId__order_simulate_get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}},{"name":"tok","in":"query","required":true,"schema":{"type":"string","title":"Tok"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/webhooks/stripe":{"post":{"tags":["DFY Vending"],"summary":"Stripe webhook (machine orders)","description":"checkout.session.completed for DFY machine orders. Signature-verified,\nidempotent on the Stripe event id.","operationId":"stripe_webhook_api_v1_dfy_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/ship":{"post":{"tags":["DFY Vending"],"summary":"Record the shipment","operationId":"ship_api_v1_dfy_deals__dealId__ship_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/install/start":{"post":{"tags":["DFY Vending"],"summary":"Start the setup wizard","operationId":"install_start_api_v1_dfy_deals__dealId__install_start_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallStartRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/install/link":{"post":{"tags":["DFY Vending"],"summary":"Link the registered machine serial","operationId":"install_link_api_v1_dfy_deals__dealId__install_link_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkMachineRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/install/checks":{"get":{"tags":["DFY Vending"],"summary":"Live install verification","operationId":"install_checks_api_v1_dfy_deals__dealId__install_checks_get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/install/complete":{"post":{"tags":["DFY Vending"],"summary":"Flip the deal LIVE","operationId":"install_complete_api_v1_dfy_deals__dealId__install_complete_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteInstallRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/install/dispatch":{"post":{"tags":["DFY Vending"],"summary":"Dispatch the install to the Kiosk-X team","operationId":"install_dispatch_api_v1_dfy_deals__dealId__install_dispatch_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DispatchInstallRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/install/orders":{"get":{"tags":["DFY Vending"],"summary":"Install work-order queue","operationId":"install_orders_api_v1_dfy_install_orders_get","parameters":[{"name":"assignee","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assignee"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/install/orders/{workOrderId}":{"post":{"tags":["DFY Vending"],"summary":"Installer queue transition","operationId":"update_install_order_api_v1_dfy_install_orders__workOrderId__post","parameters":[{"name":"workOrderId","in":"path","required":true,"schema":{"type":"string","title":"Workorderid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallOrderUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/portfolio/settings":{"get":{"tags":["DFY Vending"],"summary":"Portfolio autopilot settings","operationId":"get_settings_api_v1_dfy_portfolio_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["DFY Vending"],"summary":"Update autopilot settings","operationId":"put_settings_api_v1_dfy_portfolio_settings_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsPatch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/autopilot":{"post":{"tags":["DFY Vending"],"summary":"Per-deal autopilot override","operationId":"deal_autopilot_api_v1_dfy_deals__dealId__autopilot_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealAutopilotRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/autopilot/tick":{"post":{"tags":["DFY Vending"],"summary":"Run one autopilot pass (deals + inventory)","operationId":"autopilot_tick_api_v1_dfy_autopilot_tick_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/portfolio":{"get":{"tags":["DFY Vending"],"summary":"Portfolio home — \"all you see is revenue\"","operationId":"portfolio_api_v1_dfy_portfolio_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/portfolio/securities":{"get":{"tags":["DFY Vending"],"summary":"Securities view — revenue/sales/PROFIT per machine","description":"The Robinhood view: every machine as a security — MTD revenue, sales,\nfull cost lines and PROFIT, with its operating-mode badge. Aggregates\ncorrectly regardless of mode; estimated components stay badged.","operationId":"securities_api_v1_dfy_portfolio_securities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/mode/{kind}/{ident}":{"get":{"tags":["DFY Vending"],"summary":"Operating mode of a machine or deal","operationId":"get_mode_api_v1_dfy_mode__kind___ident__get","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","title":"Kind"}},{"name":"ident","in":"path","required":true,"schema":{"type":"string","title":"Ident"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["DFY Vending"],"summary":"Flip capability toggles / apply a preset","description":"Set the operating mode. Mid-lifecycle transitions are DEFINED here:\nnegotiation off = agent halts + hands the thread over; negotiation back\non = resume-from-current-terms after a checkpoint ack; inventory off =\nqueued (unapproved) orders cancelled, placed ones stand; install off =\nan unassigned work order is cancelled.","operationId":"put_mode_api_v1_dfy_mode__kind___ident__put","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","title":"Kind"}},{"name":"ident","in":"path","required":true,"schema":{"type":"string","title":"Ident"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModePatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/mode/{kind}/{ident}/concierge":{"post":{"tags":["DFY Vending"],"summary":"Concierge tier — hand it to Operator X (paid, reversible)","operationId":"concierge_api_v1_dfy_mode__kind___ident__concierge_post","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","title":"Kind"}},{"name":"ident","in":"path","required":true,"schema":{"type":"string","title":"Ident"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConciergeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/resume-ack":{"post":{"tags":["DFY Vending"],"summary":"Ack the agent resuming a hand-run negotiation","operationId":"resume_ack_api_v1_dfy_deals__dealId__negotiation_resume_ack_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/advise":{"post":{"tags":["DFY Vending"],"summary":"Negotiation ADVISOR — what would the agent do? (suggest-only)","operationId":"negotiation_advise_api_v1_dfy_deals__dealId__negotiation_advise_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/negotiation/operator-turn":{"post":{"tags":["DFY Vending"],"summary":"Operator-authored negotiation turn (manual mode)","operationId":"negotiation_operator_turn_api_v1_dfy_deals__dealId__negotiation_operator_turn_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorTurnRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/assist/outreach-draft":{"post":{"tags":["DFY Vending"],"summary":"Pulse Mailer — draft the intro email (you send it)","operationId":"assist_outreach_draft_api_v1_dfy_deals__dealId__assist_outreach_draft_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutreachDraftRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/inventory/suggestions":{"get":{"tags":["DFY Vending"],"summary":"Fleet Foreman restock suggestions (suggest-only)","operationId":"inventory_suggestions_api_v1_dfy_inventory_suggestions_get","parameters":[{"name":"machineNo","in":"query","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/checkpoints":{"get":{"tags":["DFY Vending"],"summary":"Checkpoint inbox","operationId":"checkpoints_api_v1_dfy_checkpoints_get","parameters":[{"name":"includeResolved","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Includeresolved"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/checkpoints/{checkpointId}/resolve":{"post":{"tags":["DFY Vending"],"summary":"Resolve (skip) an inbox checkpoint","description":"Dismiss a checkpoint from the inbox without taking the underlying\naction. Action endpoints (approve target/terms, send lease, approve\norder) still auto-resolve their own checkpoints — this is the explicit\n\"Skip\" for items the operator has decided not to act on.","operationId":"resolve_checkpoint_api_v1_dfy_checkpoints__checkpointId__resolve_post","parameters":[{"name":"checkpointId","in":"path","required":true,"schema":{"type":"string","title":"Checkpointid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/notifications":{"get":{"tags":["DFY Vending"],"summary":"DFY notifications","operationId":"notifications_api_v1_dfy_notifications_get","parameters":[{"name":"unreadOnly","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Unreadonly"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/notifications/read":{"post":{"tags":["DFY Vending"],"summary":"Mark notifications read","operationId":"mark_read_api_v1_dfy_notifications_read_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkReadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/inventory/orders":{"get":{"tags":["DFY Vending"],"summary":"Supplier orders (auto-inventory)","operationId":"inventory_orders_api_v1_dfy_inventory_orders_get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/inventory/tick":{"post":{"tags":["DFY Vending"],"summary":"Run the auto-inventory agent once","operationId":"inventory_tick_api_v1_dfy_inventory_tick_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/inventory/orders/{orderId}/approve":{"post":{"tags":["DFY Vending"],"summary":"Approve/skip an over-cap supplier order (checkpoint: money)","operationId":"approve_order_api_v1_dfy_inventory_orders__orderId__approve_post","parameters":[{"name":"orderId","in":"path","required":true,"schema":{"type":"string","title":"Orderid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/inventory/orders/{orderId}/receive":{"post":{"tags":["DFY Vending"],"summary":"Refill happened — restock + settle actual cost","operationId":"receive_order_api_v1_dfy_inventory_orders__orderId__receive_post","parameters":[{"name":"orderId","in":"path","required":true,"schema":{"type":"string","title":"Orderid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceiveOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/free-product-program":{"get":{"tags":["Free-product play program"],"summary":"Get the machine's free-product program config","operationId":"get_program_api_v1_machines__machineNo__free_product_program_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Free-product play program"],"summary":"Enable/disable the free-product program on a machine","description":"Per-machine control of the QuestX \"earn a free product\" flow.\n\nEnabling turns on the shopper QR page (``/play?machine=...``) and injects\nthe program's house creatives into the machine's attract loop. ``maxPrice``\ncaps which products a credit can redeem.\n\nEnabling also registers the machine as a QuestX kiosk (``hardwareId`` =\nmachine number) so the shopper page offers real quests instead of \"This\nmachine isn't linked to QuestX yet\". The outcome is reported under\n``questx`` in the response; a failed link never blocks the program (see\n:mod:`app.questx_link` for the failure model).","operationId":"update_program_api_v1_machines__machineNo__free_product_program_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgramUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/play-qr":{"get":{"tags":["Free-product play program"],"summary":"Printable 'earn a free product' QR (PNG)","description":"QuestX-branded QR (the free-product program is QuestX-powered, prizes\nare claimed on quest-x.ai) encoding this machine's shopper play URL\n(``/play?machine=...``) — print it on the kiosk next to the offer.","operationId":"play_qr_api_v1_machines__machineNo__play_qr_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":1024,"minimum":240,"default":640,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/play/report":{"get":{"tags":["Free-product play program"],"summary":"Free-product giveaway report","description":"Promo giveaways as their own accounting category: redemption counts,\nretail value given away ($0 revenue by construction), per-machine\nbreakdown, credit-code funnel, and recent redemptions.","operationId":"play_report_api_v1_play_report_get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/prize-mechanics":{"get":{"tags":["Prize mechanics (QuestX)"],"summary":"Get the machine's prize-mechanics config (spin / scratch / draws)","operationId":"get_prize_program_api_v1_machines__machineNo__prize_mechanics_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Prize mechanics (QuestX)"],"summary":"Enable/disable prize mechanics + prize caps + promo budget","description":"Per-machine control of the QuestX prize mechanics (like the\nfree-product program flag). Enabling a mechanic turns on its shopper QR\npage and injects its house creative into the machine's attract loop.","operationId":"update_prize_program_api_v1_machines__machineNo__prize_mechanics_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgramUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/prize-qr":{"get":{"tags":["Prize mechanics (QuestX)"],"summary":"Printable scan-to-play QR for a mechanic (PNG)","operationId":"prize_qr_api_v1_machines__machineNo__prize_qr_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"mechanic","in":"query","required":false,"schema":{"type":"string","pattern":"^(spin|scratch|draws)$","default":"spin","title":"Mechanic"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":1024,"minimum":240,"default":640,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/prizes/report":{"get":{"tags":["Prize mechanics (QuestX)"],"summary":"Prize-mechanics report (plays / wins / prize cost)","description":"Scans → entries → plays → wins funnel, gross pay-to-play revenue,\nproduct-prize cost (wholesale basis), credit funnel, draw outcomes, and\npromo-budget consumption — per machine per mechanic.","operationId":"prizes_report_api_v1_prizes_report_get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/accounts":{"get":{"tags":["Accounts"],"summary":"List operator accounts","description":"Every operator on the platform, with the size of their fleet.\n\nThis is what lets a platform admin pick whose books to look at. Without it,\nan admin's cross-tenant reads return every operator's rows blended into one\ntotal, which is not a view of anything. Requires accounts:admin, so an\noperator can never enumerate their competitors.","operationId":"list_accounts_api_v1_accounts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Accounts"],"summary":"Create account","description":"Creates a new operator account (Master Account role). Requires accounts:admin.","operationId":"create_account_api_v1_accounts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountRequest"}}},"required":true},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":200,"message":"success","data":{"id":"a3f8c2e14b9d4d6c8f1e2a7b5c9d0e3f","email":"operator@example.com","name":"New Operator","phone":"+12125550100","timeZone":"America/New_York","country":"US","region":"NY","createdAt":"2026-08-10T12:00:00.000+0000"}}}}},"400":{"description":"Bad request — invalid or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":400,"message":"Bad request — invalid or missing parameters","data":null}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":401,"message":"Invalid API key","data":null}}}},"403":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":403,"message":"Insufficient scope","data":null}}}},"429":{"description":"Hourly rate limit exceeded (Retry-After: 3600)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"},"example":{"code":429,"message":"Rate limit exceeded","data":null}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payouts/statement/share":{"post":{"tags":["Host statement share"],"summary":"Mint a forwardable host-statement link","operationId":"mint_share_api_v1_payouts_statement_share_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/payouts/statement/share/revoke":{"post":{"tags":["Host statement share"],"summary":"Revoke a forwarded host-statement link","operationId":"revoke_share_api_v1_payouts_statement_share_revoke_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/public/host-statement/{token}":{"get":{"tags":["Host statement share"],"summary":"Host-facing statement (no sign-in)","description":"A host uses the product by reading the statement the operator forwarded.\n\nNo ``authenticate`` on purpose: the token *is* the credential, scoped to\none venue. Unknown, expired, and revoked tokens 404 with the same body,\nwhether the client asked for HTML or JSON — the Accept header is not an\nexistence oracle.","operationId":"public_host_statement_api_v1_public_host_statement__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets":{"get":{"tags":["Power banks"],"summary":"List Cabinets","operationId":"list_cabinets_api_v1_powerbank_cabinets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}":{"get":{"tags":["Power banks"],"summary":"Get Cabinet","operationId":"get_cabinet_api_v1_powerbank_cabinets__reference__get","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}/refresh":{"post":{"tags":["Power banks"],"summary":"Refresh Cabinet","operationId":"refresh_cabinet_api_v1_powerbank_cabinets__reference__refresh_post","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}/bind":{"post":{"tags":["Power banks"],"summary":"Bind Cabinet","description":"Attach a cabinet to a machine record so revenue and ownership work.","operationId":"bind_cabinet_api_v1_powerbank_cabinets__reference__bind_post","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}/slots/{slot}/disable":{"post":{"tags":["Power banks"],"summary":"Set Slot Disabled","operationId":"set_slot_disabled_api_v1_powerbank_cabinets__reference__slots__slot__disable_post","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}},{"name":"slot","in":"path","required":true,"schema":{"type":"integer","title":"Slot"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}/eject":{"post":{"tags":["Power banks"],"summary":"Operator Eject","description":"Free test vend / maintenance eject. Never creates a rental.\n\nDeliberately separate from the paid path: an operator standing at a\ncabinet needs to prove a slot works without a card, and a maintenance\neject that quietly opened a billing record would be worse than useless.","operationId":"operator_eject_api_v1_powerbank_cabinets__reference__eject_post","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}/rules":{"post":{"tags":["Power banks"],"summary":"Push Rules","operationId":"push_rules_api_v1_powerbank_cabinets__reference__rules_post","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/rentals":{"get":{"tags":["Power banks"],"summary":"List Rentals","operationId":"list_rentals_api_v1_powerbank_rentals_get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"type":"string","default":"","title":"Machineno"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/rentals/{rental_id}":{"get":{"tags":["Power banks"],"summary":"Get Rental","operationId":"get_rental_api_v1_powerbank_rentals__rental_id__get","parameters":[{"name":"rental_id","in":"path","required":true,"schema":{"type":"string","title":"Rental Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/tariff":{"get":{"tags":["Power banks"],"summary":"Get Tariff","description":"Defaults plus this operator's override — what Operator X edits.","operationId":"get_tariff_api_v1_powerbank_tariff_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Power banks"],"summary":"Put Tariff","description":"Set the fleet-wide power-bank prices customers see on the door page.\n\nLive rentals keep the terms they were opened with. Empty body clears the\noverride and the sticker goes back to the published defaults.","operationId":"put_tariff_api_v1_powerbank_tariff_put","requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}/tariff":{"get":{"tags":["Power banks"],"summary":"Get Cabinet Tariff","operationId":"get_cabinet_tariff_api_v1_powerbank_cabinets__reference__tariff_get","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Power banks"],"summary":"Put Cabinet Tariff","description":"Override prices on one station. Empty body clears the cabinet override.","operationId":"put_cabinet_tariff_api_v1_powerbank_cabinets__reference__tariff_put","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/cabinets/{reference}/sticker.png":{"get":{"tags":["Power banks"],"summary":"Cabinet Sticker","description":"Operator download of the print-ready door sticker.","operationId":"cabinet_sticker_api_v1_powerbank_cabinets__reference__sticker_png_get","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/stickers":{"get":{"tags":["Power banks"],"summary":"List Stickers","description":"Every owned cabinet's rent URL + QR + print sticker.","operationId":"list_stickers_api_v1_powerbank_stickers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/stickers/print":{"get":{"tags":["Power banks"],"summary":"Print Stickers","description":"Print sheet: peel these, cover the vendor Qbee codes.","operationId":"print_stickers_api_v1_powerbank_stickers_print_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/powerbank/health":{"get":{"tags":["Power banks"],"summary":"Powerbank Health","operationId":"powerbank_health_api_v1_powerbank_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/game/stats":{"get":{"tags":["Multiplayer game"],"summary":"Multiplayer game stats","description":"Sessions, scans, players, and rewards for the QR game on your fleet\n(qrType \"game\" attribution rows, one per machine).","operationId":"game_stats_api_v1_game_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/game/nakama-health":{"get":{"tags":["Multiplayer game"],"summary":"Nakama match health per kiosk","description":"Last bound match, observer join/fail, and working/sick/off/quiet.\n\nKitchen BFF only — no Nakama URL or server key. Quiet = never bound.\nSick = referee failed to join. Working = observer joined (or validation off\nafter a bind, so we do not guess a fail).","operationId":"game_nakama_health_api_v1_game_nakama_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/game/machines/{machine_no}/config":{"get":{"tags":["Multiplayer game"],"summary":"Get game config for a machine","operationId":"get_game_config_api_v1_game_machines__machine_no__config_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Multiplayer game"],"summary":"Enable/disable the game on a machine","operationId":"set_game_config_api_v1_game_machines__machine_no__config_put","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameConfigBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/analytics":{"get":{"tags":["Games LiveOps"],"summary":"Games LiveOps rollup","description":"Titles, kiosks, health chips, and hero $. Money is the revenue ledger.","operationId":"games_analytics_api_v1_games_analytics_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive","title":"From"},"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive"},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)","title":"To"},"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/funnel":{"get":{"tags":["Games LiveOps"],"summary":"Games LiveOps funnel","description":"Leaky bucket: Arcade · GameWorld · Prizes · Worlds · Quest giveaway.\n\nGameWorld includes ``nakama_match_bound`` and observer ok/fail. A referee\nfail paints that step red — session started is not treated as a good round.\nEmpty windows are zeros, not a crash. Halo snacks are same-kiosk ≤10 min\nand are never mixed into ticket $.","operationId":"games_funnel_api_v1_games_funnel_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive","title":"From"},"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive"},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)","title":"To"},"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/pointers":{"get":{"tags":["Games LiveOps"],"summary":"Games LiveOps pointers","description":"Top leaks (max 3). Quiet+online, sick, continue-low, win-no-vend.\n\nRanked in the kitchen. Serials only — no emails. Empty list if nothing\nis wrong, never a crash.","operationId":"games_pointers_api_v1_games_pointers_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive","title":"From"},"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive"},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)","title":"To"},"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/export":{"get":{"tags":["Games LiveOps"],"summary":"Games LiveOps CSV (kiosks, no names or emails)","description":"Spreadsheet of jars for the same window as analytics.\n\nColumns are serial + health + ticket $ vs snack $. Machine names and\noperator emails are omitted on purpose — a file that leaves the office\nmust not name a person.","operationId":"games_export_api_v1_games_export_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive","title":"From"},"description":"Period start (YYYY-MM-DD or ISO datetime), inclusive"},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)","title":"To"},"description":"Period end (YYYY-MM-DD inclusive, or ISO datetime exclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/machines/{machine_no}/catalog":{"get":{"tags":["Games LiveOps"],"summary":"Arcade catalog for a kiosk","operationId":"get_catalog_api_v1_games_machines__machine_no__catalog_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Games LiveOps"],"summary":"Set arcade catalog for a kiosk","operationId":"set_catalog_api_v1_games_machines__machine_no__catalog_put","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/control":{"put":{"tags":["Games LiveOps"],"summary":"Bulk catalog / GameWorld / prizes (max 25)","operationId":"bulk_control_api_v1_games_control_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkControlBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/catalog-default":{"get":{"tags":["Games LiveOps"],"summary":"Arcade catalog flag for new kiosks","operationId":"get_catalog_default_api_v1_games_catalog_default_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Games LiveOps"],"summary":"Set arcade catalog flag for new kiosks","operationId":"put_catalog_default_api_v1_games_catalog_default_put","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/cabinet-experiments/{experiment_id}/promote":{"post":{"tags":["Games LiveOps"],"summary":"Promote arcade look winner to the new-kiosk catalog flag","operationId":"promote_cabinet_experiment_api_v1_games_cabinet_experiments__experiment_id__promote_post","parameters":[{"name":"experiment_id","in":"path","required":true,"schema":{"type":"string","title":"Experiment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/live-quests":{"get":{"tags":["Games LiveOps"],"summary":"List live quest A/B tests (Nakama Satori)","operationId":"list_live_quests_api_v1_games_live_quests_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/live-quests/{experiment_id}":{"get":{"tags":["Games LiveOps"],"summary":"Live quest funnel / z-test card","operationId":"live_quest_results_api_v1_games_live_quests__experiment_id__get","parameters":[{"name":"experiment_id","in":"path","required":true,"schema":{"type":"string","title":"Experiment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/live-quests/{experiment_id}/declare":{"post":{"tags":["Games LiveOps"],"summary":"Declare live-quest winner","operationId":"live_quest_declare_api_v1_games_live_quests__experiment_id__declare_post","parameters":[{"name":"experiment_id","in":"path","required":true,"schema":{"type":"string","title":"Experiment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeclareBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/live-quests/{experiment_id}/undo":{"post":{"tags":["Games LiveOps"],"summary":"Undo live-quest promote","operationId":"live_quest_undo_api_v1_games_live_quests__experiment_id__undo_post","parameters":[{"name":"experiment_id","in":"path","required":true,"schema":{"type":"string","title":"Experiment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/games/arcade-rooms":{"get":{"tags":["Games LiveOps"],"summary":"Live cabinet arcade rooms (Nakama labels)","description":"Cabinet matches labeled ``kiosk:{game}:t={titleUuid}:m={machineNo}``.\n\nKitchen only. Never QuizVerse. Empty list if nothing is live — not a crash.","operationId":"arcade_rooms_api_v1_games_arcade_rooms_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/connectors":{"get":{"tags":["Operator OS","Engagement OS"],"summary":"Connector health — which seams are live","description":"Honest configured/unconfigured state of every engagement connector,\nwith the exact secrets an admin must set. No key material ever leaves.","operationId":"connectors_api_v1_operator_os_engagement_connectors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/contacts":{"get":{"tags":["Operator OS","Engagement OS"],"summary":"Player/venue contacts (the audience ledger)","operationId":"contacts_api_v1_operator_os_engagement_contacts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/prospects":{"get":{"tags":["Operator OS","Engagement OS"],"summary":"Partner BD prospect pipeline","operationId":"prospects_api_v1_operator_os_engagement_prospects_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/events":{"get":{"tags":["Operator OS","Engagement OS"],"summary":"Telemetry events (stock-out / machine-down / churn-risk)","description":"Scans the live exception map + contact ledger and returns the event\nstream that feeds Lifecycle Orchestrator (idempotent upsert).","operationId":"events_api_v1_operator_os_engagement_events_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/threads":{"get":{"tags":["Operator OS","Engagement OS"],"summary":"Omnichannel threads (Channel Router memory)","operationId":"threads_api_v1_operator_os_engagement_threads_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/threads/{threadId}/inbound":{"post":{"tags":["Operator OS","Engagement OS"],"summary":"Append an inbound turn to a thread","description":"The inbound seam: email/chat/voice webhooks (or the demo console) land\ncustomer messages here; Channel Router picks them up on its next plan.","operationId":"thread_inbound_api_v1_operator_os_engagement_threads__threadId__inbound_post","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string","title":"Threadid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/actions":{"get":{"tags":["Operator OS","Engagement OS"],"summary":"Outbound-action audit (what the agents actually did)","operationId":"actions_api_v1_operator_os_engagement_actions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/engagement/journeys":{"get":{"tags":["Operator OS","Engagement OS"],"summary":"Journey bundles + activation state (section E)","operationId":"journeys_api_v1_operator_os_engagement_journeys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator OS","Engagement OS"],"summary":"Activate / deactivate a journey stage","description":"Lighting a stage unlocks its agent bundle (core + engagement flavors)\non web and app — the unlock evaluates server-side in agent_states.","operationId":"set_journey_api_v1_operator_os_engagement_journeys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JourneyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/agents":{"get":{"tags":["Operator OS"],"summary":"Agent flavors + live unlock states","description":"The unlock ladder, evaluated server-side against the caller's fleet.\nBoth UIs render exactly this — locked agents show the honest reason.","operationId":"list_agents_api_v1_operator_os_agents_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/roles":{"post":{"tags":["Operator OS"],"summary":"Assign operator-OS segments to an email","operationId":"set_roles_api_v1_operator_os_roles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RolesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/exceptions":{"get":{"tags":["Operator OS"],"summary":"Exception map — only machines that need you","description":"Pins for broken / stocked-out / predicted-stock-out machines only,\nwith severity and USD at risk. Healthy machines are excluded here (see\n/health-map for the full-fleet view).","operationId":"exceptions_api_v1_operator_os_exceptions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/health-map":{"get":{"tags":["Operator OS"],"summary":"Full-fleet red/yellow/green health map","operationId":"health_map_api_v1_operator_os_health_map_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/machines/{machineNo}/story":{"get":{"tags":["Operator OS"],"summary":"Tap pin → the machine's story","description":"Status, last sale, top empty SKU, last visit, ONE recommended action.","operationId":"story_api_v1_operator_os_machines__machineNo__story_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/agents/{flavor}/plan":{"post":{"tags":["Operator OS"],"summary":"Generate the agent's ONE plan","description":"Map of pain → one AI plan. Grounded and schema-validated: machines\nmust exist in your fleet, actions come from the allowed set, dollar\nfigures trace to the risk model / revenue ledger. LLM phrasing via the\nLiteLLM gateway; deterministic fallback always available.","operationId":"generate_plan_api_v1_operator_os_agents__flavor__plan_post","parameters":[{"name":"flavor","in":"path","required":true,"schema":{"type":"string","title":"Flavor"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_os__PlanRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/plans/{planId}":{"get":{"tags":["Operator OS"],"summary":"Fetch a plan","operationId":"get_plan_api_v1_operator_os_plans__planId__get","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/plans/{planId}/steps/{stepId}/execute":{"post":{"tags":["Operator OS"],"summary":"One-tap execute a plan step","description":"Performs the step server-side (restock, work order, job, navigation).\nDestructive/costly actions (dispatch, work orders, jobs, SKU orders)\nreturn ``needsConfirm`` until called with ``confirm=true``.","operationId":"execute_step_api_v1_operator_os_plans__planId__steps__stepId__execute_post","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}},{"name":"stepId","in":"path","required":true,"schema":{"type":"string","title":"Stepid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_os__ExecuteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/plans/{planId}/steps/{stepId}/complete":{"post":{"tags":["Operator OS"],"summary":"Mark a step done (closes the loop)","description":"Records the visit/fix and COMPUTES risk cleared: plan-time risk minus\nthe machine's live recomputed risk — never an invented number.","operationId":"complete_step_api_v1_operator_os_plans__planId__steps__stepId__complete_post","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}},{"name":"stepId","in":"path","required":true,"schema":{"type":"string","title":"Stepid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/plans/{planId}/outcome":{"get":{"tags":["Operator OS"],"summary":"After-action: what did the plan clear","operationId":"outcome_api_v1_operator_os_plans__planId__outcome_get","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/plans/{planId}/replan":{"post":{"tags":["Operator OS"],"summary":"Dynamic re-rank against live risk","description":"Mid-day re-plan: a machine went critical → regenerate the remaining\nstops against live risk. The old plan keeps its outcome history.","operationId":"replan_api_v1_operator_os_plans__planId__replan_post","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_os__PlanRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/morning-ping":{"get":{"tags":["Operator OS"],"summary":"Shift Captain morning digest (notification payload)","operationId":"morning_api_v1_operator_os_morning_ping_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/heatmap":{"get":{"tags":["Operator OS"],"summary":"Sales heat by hour per machine (Venue Concierge)","operationId":"heatmap_api_v1_operator_os_heatmap_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/zombies":{"get":{"tags":["Operator OS"],"summary":"Relocate/retire: high cost, low yield (real ledger)","operationId":"zombie_map_api_v1_operator_os_zombies_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/pnl-geo":{"get":{"tags":["Operator OS"],"summary":"P&L by geography — margin, not vanity revenue","operationId":"pnl_geo_api_v1_operator_os_pnl_geo_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/territory-balance":{"get":{"tags":["Operator OS"],"summary":"Redraw routes for equal tech load","operationId":"territory_api_v1_operator_os_territory_balance_get","parameters":[{"name":"techs","in":"query","required":false,"schema":{"type":"integer","maximum":8,"minimum":1,"default":2,"title":"Techs"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/sku-drop":{"post":{"tags":["Operator OS"],"summary":"Push a SKU to pins — geo-clustered targets","operationId":"sku_drop_api_v1_operator_os_sku_drop_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkuDropRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/site-score":{"get":{"tags":["Operator OS"],"summary":"Score a candidate site (Location Scout seam)","operationId":"site_score_api_v1_operator_os_site_score_get","parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","maximum":90.0,"minimum":-90.0,"title":"Lat"}},{"name":"lng","in":"query","required":true,"schema":{"type":"number","maximum":180.0,"minimum":-180.0,"title":"Lng"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/jobs":{"get":{"tags":["Operator OS"],"summary":"Jobs: your own + open marketplace jobs","operationId":"list_jobs_api_v1_operator_os_jobs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator OS"],"summary":"Publish a refill/SKU job","operationId":"create_job_api_v1_operator_os_jobs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobCreateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/jobs/{jobId}/accept":{"post":{"tags":["Operator OS"],"summary":"Broker: accept an open marketplace job","operationId":"accept_job_api_v1_operator_os_jobs__jobId__accept_post","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string","title":"Jobid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_os__ExecuteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/operator-os/work-orders":{"get":{"tags":["Operator OS"],"summary":"Work orders (Coverage Guardian / dispatch)","operationId":"work_orders_api_v1_operator_os_work_orders_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/agents":{"get":{"tags":["Aahaa Surfaces"],"summary":"Consumer agents + journey-bundle unlock states","operationId":"list_agents_api_v1_aahaa_agents_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/config":{"get":{"tags":["Aahaa Surfaces"],"summary":"Aahaa Surfaces config (incl. per-machine Fortune Teller)","operationId":"get_config_api_v1_aahaa_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Aahaa Surfaces"],"summary":"Update Aahaa Surfaces config","operationId":"put_config_api_v1_aahaa_config_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/agents/{agent}/plan":{"post":{"tags":["Aahaa Surfaces"],"summary":"Generate the agent's grounded plan","operationId":"generate_plan_api_v1_aahaa_agents__agent__plan_post","parameters":[{"name":"agent","in":"path","required":true,"schema":{"type":"string","title":"Agent"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__aahaa__PlanRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/plans/{planId}":{"get":{"tags":["Aahaa Surfaces"],"summary":"Fetch a plan","operationId":"get_plan_api_v1_aahaa_plans__planId__get","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/plans/{planId}/steps/{stepId}/execute":{"post":{"tags":["Aahaa Surfaces"],"summary":"Execute a plan step (confirm-gated for money/humans)","operationId":"execute_step_api_v1_aahaa_plans__planId__steps__stepId__execute_post","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}},{"name":"stepId","in":"path","required":true,"schema":{"type":"string","title":"Stepid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__aahaa__ExecuteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/plans/{planId}/outcome":{"get":{"tags":["Aahaa Surfaces"],"summary":"Plan after-action (funnel slice)","operationId":"plan_outcome_api_v1_aahaa_plans__planId__outcome_get","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","title":"Planid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/outcomes":{"get":{"tags":["Aahaa Surfaces"],"summary":"Outcome ledger summary (estimated vs actual badged)","operationId":"outcomes_api_v1_aahaa_outcomes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/grants":{"get":{"tags":["Aahaa Surfaces"],"summary":"Reward-grant fairness ledger","operationId":"grants_api_v1_aahaa_grants_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/aahaa/fortune/funnel":{"get":{"tags":["Aahaa Surfaces"],"summary":"Fortune Teller funnel (per stage, honest counts)","description":"QR renders → scans → completions → shares → perk grants → redemptions,\ncomputed from the outcome/grants ledgers + the play-credit statuses (a\nredemption is only counted when the KX credit actually redeemed).","operationId":"fortune_funnel_api_v1_aahaa_fortune_funnel_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/briefing":{"get":{"tags":["Engagement"],"summary":"Operator Briefing — the daily-open story cards","operationId":"get_briefing_api_v1_engagement_briefing_get","parameters":[{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/briefing/viewed":{"post":{"tags":["Engagement"],"summary":"Close the daily loop (streak + missions)","operationId":"briefing_viewed_api_v1_engagement_briefing_viewed_post","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BriefingViewedRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/streak":{"get":{"tags":["Engagement"],"summary":"Operator streak","operationId":"get_streak_api_v1_engagement_streak_get","parameters":[{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/streak/touch":{"post":{"tags":["Engagement"],"summary":"Register today's qualifying action","operationId":"touch_streak_api_v1_engagement_streak_touch_post","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StreakTouchRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/prefs":{"get":{"tags":["Engagement"],"summary":"Notification + personalization preferences","operationId":"get_prefs_api_v1_engagement_prefs_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Engagement"],"summary":"Update preferences (shallow merge)","operationId":"put_prefs_api_v1_engagement_prefs_put","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrefsPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/events":{"post":{"tags":["Engagement"],"summary":"Ingest app engagement events (batch)","operationId":"ingest_events_api_v1_engagement_events_post","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/habits":{"get":{"tags":["Engagement"],"summary":"Your habits — engagement summary","operationId":"habits_api_v1_engagement_habits_get","parameters":[{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":14,"title":"Days"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/achievements":{"get":{"tags":["Engagement"],"summary":"Milestones earned + progress","operationId":"achievements_api_v1_engagement_achievements_get","parameters":[{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/missions":{"get":{"tags":["Engagement"],"summary":"Today's operator missions","operationId":"missions_api_v1_engagement_missions_get","parameters":[{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/leaderboard":{"get":{"tags":["Engagement"],"summary":"Opt-in, anonymized, fleet-size-segmented","operationId":"leaderboard_api_v1_engagement_leaderboard_get","parameters":[{"name":"metric","in":"query","required":false,"schema":{"type":"string","description":"yield_per_machine | uptime_pct","default":"yield_per_machine","title":"Metric"},"description":"yield_per_machine | uptime_pct"},{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/portfolio":{"get":{"tags":["Engagement"],"summary":"Machine portfolio — series, positions, buying power","operationId":"portfolio_api_v1_engagement_portfolio_get","parameters":[{"name":"range","in":"query","required":false,"schema":{"type":"string","description":"1D | 1W | 1M | 3M | YTD | ALL","default":"1W","title":"Range"},"description":"1D | 1W | 1M | 3M | YTD | ALL"},{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/notifications/categories":{"get":{"tags":["Engagement"],"summary":"Notification taxonomy","operationId":"categories_api_v1_engagement_notifications_categories_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/notifications/pending":{"get":{"tags":["Engagement"],"summary":"Poll deliverable notifications","description":"Evaluates the live triggers (money moment, risk) then drains the\noutbox. Consume-once: returned items are marked delivered — the app\nraises them as local notifications (or FCM does, when configured).","operationId":"pending_api_v1_engagement_notifications_pending_get","parameters":[{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone.","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (JS: -new Date().getTimezoneOffset()). A fallback: an offset cannot describe a day on the far side of a daylight-saving change. Prefer timeZone."},{"name":"timeZone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet.","title":"Timezone"},"description":"IANA zone the operator's days should be bucketed by, e.g. Pacific/Auckland. Preferred over tzOffsetMinutes, which only describes right now. Omitted, the operator's account zone is used, then a zone inferred from their fleet."},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/notifications/{notifId}/opened":{"post":{"tags":["Engagement"],"summary":"Record an open (open-through metric)","operationId":"notif_opened_api_v1_engagement_notifications__notifId__opened_post","parameters":[{"name":"notifId","in":"path","required":true,"schema":{"type":"string","title":"Notifid"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotifAck","default":{"tzOffsetMinutes":0}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/notifications/history":{"get":{"tags":["Engagement"],"summary":"Recent notification outbox","operationId":"notif_history_api_v1_engagement_notifications_history_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/devices":{"post":{"tags":["Engagement"],"summary":"Register a push token (FCM seam)","operationId":"register_device_api_v1_engagement_devices_post","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/engagement/gamification/status":{"get":{"tags":["Engagement"],"summary":"Nakama bridge + FCM readiness","operationId":"gamification_status_api_v1_engagement_gamification_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/social/profile":{"get":{"tags":["Operator Social"],"summary":"My social profile (auto-created on first read)","operationId":"get_profile_api_v1_social_profile_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Operator Social"],"summary":"Update my social profile / privacy toggles","operationId":"put_profile_api_v1_social_profile_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/social/directory":{"get":{"tags":["Operator Social"],"summary":"Find other operators (privacy-filtered)","description":"Discoverable operators, public projection only. Excludes the caller;\nexcludes anyone who opted out. Never exposes email, machine locations,\nexact machine counts, or revenue.","operationId":"directory_api_v1_social_directory_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":40,"description":"Handle / display-name search","default":"","title":"Q"},"description":"Handle / display-name search"},{"name":"region","in":"query","required":false,"schema":{"type":"string","maxLength":40,"description":"Coarse region filter","default":"","title":"Region"},"description":"Coarse region filter"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/social/profiles/by-nakama/{nakama_user_id}":{"get":{"tags":["Operator Social"],"summary":"Resolve a Nakama user id to an operator's public profile","description":"Lets the app show a friend's tier badge / avatar next to their chat.\nPublic projection only — same privacy filter as the directory (an\noperator who opted out of DISCOVERY is still resolvable by an existing\nfriend who already has their Nakama id; nothing private leaks).","operationId":"by_nakama_api_v1_social_profiles_by_nakama__nakama_user_id__get","parameters":[{"name":"nakama_user_id","in":"path","required":true,"schema":{"type":"string","title":"Nakama User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/social/share-cards":{"get":{"tags":["Operator Social"],"summary":"My shareable milestone cards (real data)","description":"Everything the signed-in operator could share into a conversation,\nrendered from live platform data and server-signed (see /cards/verify).\nSharing itself is explicit — the app sends a chosen card into a Nakama\nchat; nothing is auto-posted.","operationId":"share_cards_api_v1_social_share_cards_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/social/cards/verify":{"post":{"tags":["Operator Social"],"summary":"Verify a received share card's signature","description":"Receiving clients call this before rendering an `[opxcard]` chat payload\nas a rich, trusted card. Anything without a valid signature (hand-forged,\ntampered, or re-attributed) must render as plain text. Always 200 — the\nverdict is in the body.","operationId":"verify_card_api_v1_social_cards_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardVerify"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/social/dm/send":{"post":{"tags":["Operator Social"],"summary":"Send a DM (server-enforced friends-only)","operationId":"dm_send_api_v1_social_dm_send_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmSend"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/social/nearby":{"get":{"tags":["Operator Social"],"summary":"Fleet owners near me (coarse, opt-in)","operationId":"nearby_api_v1_social_nearby_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle":{"get":{"tags":["Machine Lifecycle"],"summary":"Where this machine is in its lifecycle","description":"The canonical lifecycle view: stage, installation flavor, hardware,\nthe acquisition pipeline with the current position, legal next\ntransitions, flavor-appropriate next actions, onboarding checks, open\nprotection claims, and the per-machine event trail. Reads reconcile the\nrecord against the DFY deal / manufacturer order / machine fragments\nfirst, so this is always the truthful rollup. Requires machines:read.","operationId":"get_lifecycle_api_v1_machines__machineNo__lifecycle_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle/transition":{"post":{"tags":["Machine Lifecycle"],"summary":"Move a machine through its lifecycle","description":"Explicit stage transition with legality enforced (illegal moves 409\nand name the legal targets). ``force`` is admin-only and lands on the\nevent trail as a forced correction. Requires machines:write.","operationId":"transition_lifecycle_api_v1_machines__machineNo__lifecycle_transition_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransitionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle/onboarding":{"get":{"tags":["Machine Lifecycle"],"summary":"Onboarding checklist (first-boot / existing-machine)","description":"The flavor-agnostic first-boot checklist: claimed, online (APK/agent\nrepointed at the Kiosk-X cloud — for existing Reyeah units that means\nthe sideloaded/OTA'd kioskx APK; for ZHZN, our agent speaking /zhzn/*),\nNayax bound (real Device Number, non-provisional), planogram stocked, and\n``boardCanDispense`` — the vend board is not in a state that would make the\nstorefront refuse a purchase. Onboarding auto-advances to live when all\nchecks pass; this endpoint is what the guided setup polls.\nRequires machines:read.","operationId":"onboarding_checklist_api_v1_machines__machineNo__lifecycle_onboarding_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle/onboarding/complete":{"post":{"tags":["Machine Lifecycle"],"summary":"Complete onboarding (flip to live)","description":"Explicit onboarding completion — normally unnecessary (checks\nauto-advance), but ``force`` covers hardware states the cloud can't\nverify. Requires machines:write.","operationId":"complete_onboarding_api_v1_machines__machineNo__lifecycle_onboarding_complete_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingCompleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle/relocate":{"post":{"tags":["Machine Lifecycle"],"summary":"Start relocating a machine","description":"live → relocating. Captures the destination; completing the move\nwrites it onto the machine record and returns the machine to live.\nRequires machines:write.","operationId":"start_relocation_api_v1_machines__machineNo__lifecycle_relocate_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelocateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle/relocate/complete":{"post":{"tags":["Machine Lifecycle"],"summary":"Complete a relocation","description":"relocating → live; the captured destination becomes the machine's\nlocation/pin. An address-only destination is geocoded server-side (same\nseam as PATCH /machines/{no} {address}) so the map pin moves with the\nlabel; a downed geocoder degrades to the label-only update with the\ndetail recorded on the event trail — completion never fails on it.\nRequires machines:write.","operationId":"complete_relocation_api_v1_machines__machineNo__lifecycle_relocate_complete_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle/retire":{"post":{"tags":["Machine Lifecycle"],"summary":"Retire / resell / return a machine (end of life)","description":"The richer end-of-life flow on top of decommission: the serial\nreturns to the unclaimed pool (Nayax Device Number freed, revenue\nhistory stays on your books) and the lifecycle tenure closes as\nretired/resold/returned. For resale/transfer the next operator claims\nthe same serial via POST /api/v1/machines/register — that claim starts\na fresh lifecycle tenure at onboarding. Requires machines:write.\n\n**The cabinet also leaves your balance sheet, as a disposal.** Its cost\nand its accumulated depreciation come off together, ``proceedsUsd`` (if\nany) is banked as cash, and the difference against net book value is\nrecognised as a gain or loss on disposal — dated the moment it left, so\ndepreciation stops accruing there. The entry is on the balance sheet\nunder ``machineDisposals`` and the cabinet stays readable afterwards at\nGET /api/v1/machine-assets/retired, which is where its cost and the\ndepreciation you claimed live for the tax year you disposed of it in.","operationId":"retire_machine_api_v1_machines__machineNo__lifecycle_retire_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetireRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/claims":{"post":{"tags":["Machine Lifecycle"],"summary":"File a protection-plan claim","description":"Files a claim against the machine's ACTIVE protection coverage\n(app/protection.py rider states; uncovered machines 409 with the enroll\npointer). Opens a ``protection_repair`` work order on the Operator OS\nqueue and moves a live machine into ``maintenance``. Requires\nmachines:write.","operationId":"open_claim_api_v1_machines__machineNo__claims_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimOpenRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"get":{"tags":["Machine Lifecycle"],"summary":"Claims for a machine","operationId":"machine_claims_api_v1_machines__machineNo__claims_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/claims":{"get":{"tags":["Machine Lifecycle"],"summary":"List protection-plan claims","operationId":"list_claims_api_v1_claims_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/claims/{claimId}/advance":{"post":{"tags":["Machine Lifecycle"],"summary":"Advance a claim (approve / repair / resolve / deny)","description":"Claim workflow: open → approved → in_repair → resolved (or denied).\nResolution closes the repair work order and returns the machine to\n``live`` once no other claim is open. Requires machines:write.","operationId":"advance_claim_api_v1_claims__claimId__advance_post","parameters":[{"name":"claimId","in":"path","required":true,"schema":{"type":"string","title":"Claimid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimAdvanceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/fleet/lifecycle":{"get":{"tags":["Machine Lifecycle"],"summary":"Fleet lifecycle rollup (stage × flavor)","description":"Every machine's lifecycle position in one response: counts by stage,\ncounts by installation flavor, and the per-machine rows the fleet\nlifecycle board renders. Reconciles all fragments first. Requires\nmachines:read.","operationId":"fleet_lifecycle_api_v1_fleet_lifecycle_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/alerts":{"get":{"tags":["Alerts"],"summary":"Machine alerts feed (offline / recovery)","description":"Newest-first transition feed for the caller's fleet (admin: everyone).\n\n``status=open`` is the console's red-badge query: offline alerts nobody\nhas recovered from yet. Walk-ups (``kind=walkup_detected``) ride the same\nfeed but are news, not trouble: ``openCount`` never counts them —\n``walkupsOpen`` does.","operationId":"list_alerts_api_v1_alerts_get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Machineno"}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/alerts/webhook":{"get":{"tags":["Alerts"],"summary":"Read the operator's alert webhook","operationId":"get_webhook_api_v1_alerts_webhook_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Alerts"],"summary":"Set the operator's alert webhook","description":"Store the webhook on the operator account. One URL per operator —\nan alert router (Slack bridge, PagerDuty ingest, n8n flow) fans out from\nthere; this gateway does not grow a subscription matrix.","operationId":"set_webhook_api_v1_alerts_webhook_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/legal/esign-disclosure":{"get":{"tags":["Legal"],"summary":"Electronic-records disclosure (pre-signature)","description":"The disclosure a signer must see and affirmatively accept BEFORE a\nsigning link is issued. Public: signing UIs (web console, Operator X)\nrender this text next to the consent checkbox. The accepted version is\nstored with the envelope.","operationId":"esign_disclosure_api_v1_legal_esign_disclosure_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/legal/templates":{"get":{"tags":["Legal"],"summary":"Contract template catalog (clause maps)","description":"The platform's contract instruments: what each document is, why that\ninstrument was chosen, and its section map — rendered from the versioned\nclause library (app/legal/templates/), the source of truth the Documenso\ntemplates are generated from.","operationId":"template_catalog_api_v1_legal_templates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/legal/archives":{"get":{"tags":["Legal"],"summary":"List archived executed contracts","description":"The immutable S3 archive for one deal/plan: the sealed signed PDF,\nthe Documenso audit log (completion certificate evidence) and the\nenvelope metadata (including the stored ESIGN consent). Links are\nshort-lived presigned URLs — the bucket is never public.","operationId":"list_archives_api_v1_legal_archives_get","parameters":[{"name":"kind","in":"query","required":true,"schema":{"type":"string","description":"Archive kind, e.g. placement-license / protection-plan","title":"Kind"},"description":"Archive kind, e.g. placement-license / protection-plan"},{"name":"ref","in":"query","required":true,"schema":{"type":"string","description":"Deal id, or subscriptionId/machineNo","title":"Ref"},"description":"Deal id, or subscriptionId/machineNo"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/legal/archive":{"post":{"tags":["Legal"],"summary":"Archive a completed envelope to S3","description":"Pull the sealed PDF + audit log for a COMPLETED Documenso document\nand store them immutably in S3 (manual/backfill trigger; the signing\nflows archive automatically on completion). Refuses non-completed\ndocuments. An unconfigured deployment is 503 (same honesty as\nGET /legal/archives), never a 409 — nothing about the request conflicts.","operationId":"archive_document_api_v1_legal_archive_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/enroll":{"post":{"tags":["Super-admin money ops"],"summary":"Start MFA enrollment (factors 1+2 required)","description":"otpauth:// URI + QR for the authenticator app. Requires a logged-in,\nallowlisted account AND the super-admin password — enrollment is itself\ntwo-factor. A confirmed enrollment is never replaced here.","operationId":"enroll_api_v1_superadmin_enroll_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/enroll/confirm":{"post":{"tags":["Super-admin money ops"],"summary":"Confirm MFA enrollment with a first code","operationId":"enroll_confirm_api_v1_superadmin_enroll_confirm_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmEnrollRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/session":{"get":{"tags":["Super-admin money ops"],"summary":"Session status (who am I, time left)","operationId":"session_status_api_v1_superadmin_session_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Super-admin money ops"],"summary":"Three-factor challenge → super-admin session","operationId":"open_session_api_v1_superadmin_session_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/session/logout":{"post":{"tags":["Super-admin money ops"],"summary":"Revoke the current session","operationId":"logout_api_v1_superadmin_session_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/overview":{"get":{"tags":["Super-admin money ops"],"summary":"Money-ops overview","operationId":"overview_api_v1_superadmin_overview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/investors":{"get":{"tags":["Super-admin money ops"],"summary":"Per-investor funded positions","operationId":"investors_api_v1_superadmin_investors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/investors/{email}/refund":{"post":{"tags":["Super-admin money ops"],"summary":"Refund UNALLOCATED pool capital (guarded, audited)","description":"The refund procedure's ledger leg: deduct from the operator's\nunallocated pool balance (never more than what is unallocated — capital\ninside a spawned deal must go through the exceptions queue and a deal\ncancellation first) and record the movement. The actual Stripe refund is\nexecuted in the Stripe dashboard per the manual; this keeps the platform\nledger truthful.","operationId":"refund_pool_api_v1_superadmin_investors__email__refund_post","parameters":[{"name":"email","in":"path","required":true,"schema":{"type":"string","title":"Email"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__superadmin_money__RefundRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/orders":{"get":{"tags":["Super-admin money ops"],"summary":"Every machine order + manufacturer status","operationId":"orders_api_v1_superadmin_orders_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/orders/{dealId}/place":{"post":{"tags":["Super-admin money ops"],"summary":"Place a paid order with the manufacturer","operationId":"place_order_api_v1_superadmin_orders__dealId__place_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/orders/{dealId}/status":{"post":{"tags":["Super-admin money ops"],"summary":"Manual manufacturer status update","operationId":"order_status_api_v1_superadmin_orders__dealId__status_post","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatusRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/factory":{"get":{"tags":["Super-admin money ops"],"summary":"Per-serial factory QA, sign-off and shipping","description":"Every cabinet's manufacturer paperwork, across operators.\n\nThe Orders tab is deal-level (where is this purchase?). This is serial-level\n(who built this crate, what was tested, where it shipped, who signed). The\nfactory writes the same record the operator and admin consoles read.","operationId":"factory_api_v1_superadmin_factory_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/checkpoints":{"get":{"tags":["Super-admin money ops"],"summary":"Open checkpoints across all operators","operationId":"checkpoints_api_v1_superadmin_checkpoints_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/exceptions":{"get":{"tags":["Super-admin money ops"],"summary":"Refunds/exceptions queue","operationId":"exceptions_api_v1_superadmin_exceptions_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Super-admin money ops"],"summary":"Open an exception","operationId":"open_exception_api_v1_superadmin_exceptions_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExceptionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/exceptions/{excId}/resolve":{"post":{"tags":["Super-admin money ops"],"summary":"Resolve/reject an exception","operationId":"resolve_exception_api_v1_superadmin_exceptions__excId__resolve_post","parameters":[{"name":"excId","in":"path","required":true,"schema":{"type":"string","title":"Excid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveExceptionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/audit":{"get":{"tags":["Super-admin money ops"],"summary":"Money-movement + gate audit trail","operationId":"audit_api_v1_superadmin_audit_get","parameters":[{"name":"kinds","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"comma-separated prefixes, e.g. money,gate","title":"Kinds"},"description":"comma-separated prefixes, e.g. money,gate"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/manual":{"get":{"tags":["Super-admin money ops"],"summary":"Super-admin operations manual (gated)","operationId":"manual_api_v1_superadmin_manual_get","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","pattern":"^(html|markdown)$","default":"html","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/manufacturing":{"get":{"tags":["Machine orders"],"summary":"Manufacturer order status + expected-vs-actual timeline","operationId":"manufacturing_status_api_v1_dfy_deals__dealId__manufacturing_get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/manufacturing/webhook":{"post":{"tags":["Machine orders"],"summary":"Manufacturer status webhook (shared-secret, idempotent)","operationId":"manufacturer_webhook_api_v1_manufacturing_webhook_post","parameters":[{"name":"x-manufacturer-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Manufacturer-Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/build/summary":{"get":{"tags":["Machine build & QA"],"summary":"Build & QA state across the fleet","description":"Which machines are untested, awaiting acceptance, or failing QA.","operationId":"build_summary_api_v1_machines_build_summary_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/build/tests":{"get":{"tags":["Machine build & QA"],"summary":"The factory test suite","description":"The closed set of subsystem codes, and which of them are mandatory.","operationId":"build_test_catalog_api_v1_machines_build_tests_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/build":{"get":{"tags":["Machine build & QA"],"summary":"Build record, tests and sign-offs","operationId":"get_build_api_v1_machines__machine_no__build_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Machine build & QA"],"summary":"Record what the factory built","description":"Two different claims share this route, and they have different writers.\n\n**Factory data** (manufacturer, model, board revision, build and ship dates,\nas-built firmware) stays full-admin or manufacturer-credential only: it is an\nassertion about somebody else's hardware.\n\n**The acquisition cost** is written by the operator who owns the cabinet, or\nby a full admin on any operator's behalf. It is their own purchase price, and\nit only reaches their own books — see ``_acquisition_scope``. A manufacturer\ncredential still cannot write it at all: what the operator paid is not a fact\nthe factory knows. An amendment to a cost already recorded is allowed and\nlands on the acquisition's amendment trail, because it restates the\ndepreciation and therefore the profit of every period since.","operationId":"put_build_api_v1_machines__machine_no__build_put","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/build/tests":{"post":{"tags":["Machine build & QA"],"summary":"Record factory test results","operationId":"post_tests_api_v1_machines__machine_no__build_tests_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestsIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/build/signoff":{"post":{"tags":["Machine build & QA"],"summary":"Factory QA sign-off","description":"Refused while a required test is missing or a subsystem is failing.","operationId":"post_signoff_api_v1_machines__machine_no__build_signoff_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FactorySignoffIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/build/accept":{"post":{"tags":["Machine build & QA"],"summary":"Operator accepts delivery","description":"The operator's own signature. A full admin cannot sign this on their\nbehalf: the point of the record is that the person taking delivery said so.\n\nRefused while nothing says who gets paid for the cabinet — either a CRM\nvenue lists the serial, or the operator has declared it has no host. See\n``_require_host_answered``.","operationId":"post_accept_api_v1_machines__machine_no__build_accept_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptIn","default":{"note":"","condition":"good"}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machine-assets/":{"get":{"tags":["Machine assets"],"summary":"Machines as fixed assets: cost and book value","description":"What each cabinet cost, what it is worth now, and what has been disposed\nof. The same register the balance sheet's machine line is derived from, so\nthe two cannot disagree.\n\nScoped like its two siblings below: an operator sees their own register, and\na full admin must name whose books they are reading. A cost basis is\nper-tenant, so a cross-operator answer is not a bigger register — it is four\nbusinesses' balance sheets added together under one operator's heading, and\nthe screen that renders it has no way to know. Requires machines:read.","operationId":"asset_register_api_v1_machine_assets__get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machine-assets/retired":{"get":{"tags":["Machine assets"],"summary":"Machines you have disposed of","description":"The cabinets that have left your books, grouped by the year they left.\n\nA retired serial drops into the unclaimed pool, so every read keyed on live\nownership — the machine card, the fleet list, the build record — starts\nanswering 404. That is right for the metal and wrong for the books: the\ndisposal happened inside a tax year the operator still has to file, and the\ncost, the depreciation claimed and the gain or loss recognised are all\ntheirs. Each row carries the disposal's journal entry, so the drop in the\nbalance sheet's machine line has a visible other side.\n\nScoped like every money read: an operator sees their own disposals, a full\nadmin may narrow to one operator with ``?operatorEmail=``. A cabinet a\ndifferent operator has since claimed keeps its cost and disposal visible here\n(that record is the disposing operator's) but stops carrying its name and\nbuild history (those now belong to its next life). Requires machines:read.","operationId":"retired_machines_api_v1_machine_assets_retired_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machine-assets/retired/{machine_no}":{"get":{"tags":["Machine assets"],"summary":"One machine you disposed of, in full","description":"The cabinet, its acquisition, its disposal and the tenure that ended.\n\n404 when this operator has no disposal on file for the serial — the same body\nan unknown machine gets, so a serial they never owned is indistinguishable\nfrom one that does not exist. Requires machines:read.","operationId":"retired_machine_api_v1_machine_assets_retired__machine_no__get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/identity/conflicts":{"get":{"tags":["Machine identity"],"summary":"Machines two devices are claiming","description":"Every serial with more than one device behind it.\n\nFleet-wide and admin-only: a duplicated serial is very often duplicated\n*across* operators, so the view that finds it cannot be scoped to one.","operationId":"identity_conflicts_api_v1_machines_identity_conflicts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/device-credentials/fleet":{"get":{"tags":["Machine identity"],"summary":"Which cabinets hold their own gateway credential","description":"The migration's progress bar, and the answer to one blunt question.\n\nEvery ZHZN cabinet with its credential state: ``enrolled`` (its own key),\n``fleet-secret`` (has not taken one yet), or ``revoked``. ``fleet-secret``\nrows sort first because they are the work, and armed ones first among those.\n\nThis view used to report zero while every cabinet on the fleet was\nenrollable by anyone holding the shared secret, because it asked each\nmachine for a credential, a gateway auth stamp or an agent version before\nlisting it — and a cabinet that has never enrolled has none of the three. It\nfiltered out exactly the population it existed to show. What identifies a\nZHZN cabinet before its first heartbeat is in ``_is_gateway_cabinet``.\n\n``onFleetSecret`` is the migration's progress bar: cabinets that have not\ntaken their own key. ``armed`` is the sharper number — cabinets whose\nenrolment window is open *right now*, which is the only population the fleet\nsecret can still claim. It should normally be zero, and a number that stays\nup is an install somebody walked away from.\n\n``reachableOnFleetSecret`` is the number this view owes the reader and did\nnot have. ``onFleetSecret`` counts rows, and rows are filtered to ZHZN\ncabinets; the gateway serves any machine that is simply un-enrolled, ZHZN or\nnot. On the seeded fleet that is 27 Reyeah cabinets whose planograms and\norder books the shared secret still reaches, none of which belongs on a ZHZN\nprogress bar. Both numbers are published so neither has to lie.\n\nMigration is finished when no row says ``fleet-secret``. That ends the ZHZN\nside of it; ``reachableOnFleetSecret`` is what ``KIOSKX_ZHZN_ENROLMENT`` does\n*not* close, because that setting governs enrolment and these legs sell. See\n``docs/zhzn-device-credentials.md``.\n\nScoped like the rest of the fleet reads: an operator sees their own cabinets,\na full admin sees all of them. An operator with a cabinet still on the shared\nsecret has a real thing to chase, so this is not admin-only.\n\nIt said ``None if full_admin else principal.operatorEmail``, which is the\ntenth copy of that line and the one that was not merely latent. A plain\nCognito identity in the shared pool carries ``admin=True`` without\n``accounts:admin`` and no operator identity at all, so its null operator\nreached ``dc.fleet`` as the full admin's every-tenant filter: it read the\nwhole platform's cabinets and, worse than the usual leak, which of them will\nstill hand their gateway credential to anyone with a screwdriver. Asking the\nprincipal for a scope refuses it instead.\n\nA full admin looking at one operator still has to send ``?operatorEmail=``.\nThe console's ``/api/v1/machines`` prefix already appends it; honouring it\nhere is what stops this collection listing every cabinet under that\noperator's banner. Dropping the query is the same shape as the Agents-screen\nleak: the filter is sent, the handler ignores it, the banner claims one\ntenant.","operationId":"device_credential_fleet_api_v1_machines_device_credentials_fleet_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/serials/unclaimable":{"get":{"tags":["Machine identity"],"summary":"Registered serials no operator can claim","description":"Serials admitted under the gateway's old, looser rule.\n\nThese cabinets keep working — a validation change must not brick a machine\nthat is selling product — so they are reported rather than repaired, and a\nfleet finds out from here instead of from an installer at a venue.","operationId":"unclaimable_serials_api_v1_machines_serials_unclaimable_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/identity":{"get":{"tags":["Machine identity"],"summary":"Which device answers for this machine","operationId":"get_identity_api_v1_machines__machine_no__identity_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/identity/reset":{"post":{"tags":["Machine identity"],"summary":"Clear a machine's device identity","description":"Let a replacement board adopt this machine.\n\nAdmin-only, and never available to the machine itself: a device that could\nclear its own binding would make the duplicate check meaningless, since the\ntwin would simply reset it and take over.","operationId":"reset_identity_api_v1_machines__machine_no__identity_reset_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentityResetIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/device-credential":{"get":{"tags":["Machine identity"],"summary":"This cabinet's gateway credential state","description":"Never carries key material — a key id, a generation and a history.","operationId":"get_device_credential_api_v1_machines__machine_no__device_credential_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/device-credential/arm":{"post":{"tags":["Machine identity"],"summary":"Let this cabinet claim its own credential, once","description":"Open a bounded window in which this cabinet may enrol on the fleet secret.\n\nThe fleet secret used to be enough on its own for any cabinet the cloud had\nno device id for — which is every cabinet that has never spoken to the\ngateway — so anyone who read one cabinet's disk could claim them. Enrolling\na cabinet you do not own yields a working credential for it, which reads its\noperator's planogram and opens real orders on their books, and strands the\ngenuine cabinet permanently. An arm is what replaces the secret as the thing\nthat says \"yes, this one, now\".\n\nThree bounds, and the arm is worthless without all three: one cabinet, a\nwindow measured in minutes, and one use. ``deviceId`` adds a fourth where\nthe caller is holding the unit and can read ``/etc/machine-id`` off it.\n\nThe cabinet does not need to be waiting when you arm it. The shipped agent\nretries a refused enrolment on a lengthening ladder, so arming a cabinet in\na warehouse and leaving it is a complete operation — no truck roll, and no\nordering problem between the arm and the power-on.","operationId":"arm_device_credential_api_v1_machines__machine_no__device_credential_arm_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrolmentArmIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/device-credential/disarm":{"post":{"tags":["Machine identity"],"summary":"Close an enrolment window early","description":"For an arm made against the wrong serial, or a cabinet that went back in\nthe van. Waiting out the window would be the wrong answer to the only\nreason anybody calls this.","operationId":"disarm_device_credential_api_v1_machines__machine_no__device_credential_disarm_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/device-credential/rotate":{"post":{"tags":["Machine identity"],"summary":"Issue this cabinet a fresh credential on its next call","description":"Plan a credential change with no truck roll and no downtime.\n\nNothing is minted here. The new credential is generated at the moment the\ncabinet's own next authenticated call collects it, so the secret exists for\nexactly one response and an admin never sees a cabinet's key. The cabinet\nkeeps working on its current one until it collects the new one, which is what\nmakes this safe to do to a machine that is offline: swapping now and\ndelivering later strands whichever cabinets were unreachable today.","operationId":"rotate_device_credential_api_v1_machines__machine_no__device_credential_rotate_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialActionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/device-credential/revoke":{"post":{"tags":["Machine identity"],"summary":"Kill this cabinet's credential now","description":"For a cabinet believed compromised — stolen, opened, cloned.\n\nEvery generation stops working immediately and the cabinet's calls get 403,\nwhich the shipped agents read as revocation: they stop presenting the key and\ndo not enrol themselves a replacement, because revocation would mean nothing\nfor a stolen cabinet if the cabinet could undo it.\n\nThis does not reopen enrolment. A revoked cabinet that turns out to be\nlegitimate comes back through ``POST /identity/reset``, by a named person who\nsays why — not by the machine asking the gateway again.","operationId":"revoke_device_credential_api_v1_machines__machine_no__device_credential_revoke_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialActionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/network/summary":{"get":{"tags":["Machine network"],"summary":"Network state across the fleet","description":"Which cabinets are on a weak link, on cellular, or awaiting a change.","operationId":"network_summary_api_v1_machines_network_summary_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/network":{"get":{"tags":["Machine network"],"summary":"This machine's network","description":"Current link, known networks, any pending change (passphrase masked) and\nthe change history. Never carries the service code or a passphrase.","operationId":"get_network_api_v1_machines__machine_no__network_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/network/unlock":{"post":{"tags":["Machine network"],"summary":"Admin gate for Wi-Fi changes","description":"Re-prove the admin password to get the machine's service code, its setup\naccess point, and a short-lived ticket for the change itself.","operationId":"unlock_api_v1_machines__machine_no__network_unlock_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnlockIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/network/setup-qr.png":{"get":{"tags":["Machine network"],"summary":"Join QR for the machine's setup access point","description":"The same Wi-Fi-join code the cabinet puts on its own screen.\n\nAn image cannot carry a password body, so it is gated by the unlock ticket\nthe admin-password step-up just issued. Rendering it here is what lets a\ntechnician get onto the setup network when the cabinet's screen is dark.","operationId":"setup_qr_api_v1_machines__machine_no__network_setup_qr_png_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"ticket","in":"query","required":true,"schema":{"type":"string","title":"Ticket"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/network/changes":{"post":{"tags":["Machine network"],"summary":"Queue a Wi-Fi change","description":"Deliver new credentials on the machine's next check-in.\n\nOnly useful while the machine can still hear us — a cabinet that is already\ndark needs the on-site path instead, which is why the console offers this\none only for machines that are online or on LTE.","operationId":"queue_change_api_v1_machines__machine_no__network_changes_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"delete":{"tags":["Machine network"],"summary":"Cancel a queued change","operationId":"cancel_change_api_v1_machines__machine_no__network_changes_delete","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/network/reveal":{"post":{"tags":["Machine network"],"summary":"Re-read a queued passphrase","description":"Show the queued passphrase in clear. Requires the admin password again\n(not just an unlock ticket) and writes its own audit row, so a credential\ncan never be re-read without leaving a trace.","operationId":"reveal_api_v1_machines__machine_no__network_reveal_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Ignored for operator credentials."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__machine_network__RevealIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/agent/releases":{"get":{"tags":["ZHZN agent releases"],"summary":"Published ZHZN agent releases","operationId":"list_releases_api_v1_agent_releases_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["ZHZN agent releases"],"summary":"Publish a signed ZHZN agent release","description":"Register an artifact CI has already uploaded.\n\nPublishing does not offer the release to anything — a published release with\nno rollout aimed at it reaches zero cabinets. Separating the two means the\nbuild that lands on main is never, by itself, the build the fleet installs.","operationId":"publish_release_api_v1_agent_releases_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__agent_releases__ReleaseIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/agent/rollout":{"get":{"tags":["ZHZN agent releases"],"summary":"The ZHZN agent rollout in flight","operationId":"get_rollout_api_v1_agent_rollout_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["ZHZN agent releases"],"summary":"Aim the fleet at a published release","operationId":"put_rollout_api_v1_agent_rollout_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RolloutIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/agent/rollout/hold":{"post":{"tags":["ZHZN agent releases"],"summary":"Stop offering the rollout to new cabinets","description":"The brake. Cabinets already on the target keep it; nobody else is offered\nit. Deliberately does not roll anything back — an operator holding a rollout\nis stopping the bleeding, and deciding what to do next is a separate act.","operationId":"hold_rollout_api_v1_agent_rollout_hold_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhaseIn","default":{"reason":""}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/agent/rollout/resume":{"post":{"tags":["ZHZN agent releases"],"summary":"Resume a held rollout","operationId":"resume_rollout_api_v1_agent_rollout_resume_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhaseIn","default":{"reason":""}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/agent/fleet":{"get":{"tags":["ZHZN agent releases"],"summary":"What agent version every ZHZN cabinet is running","description":"Coverage from the versions cabinets report themselves.\n\nScoped for an operator, whole-fleet for an admin: a rollout is a\nplatform-wide act but its consequences land on one operator's machines, so\nthey must be able to see it without asking.","operationId":"fleet_coverage_api_v1_agent_fleet_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/agent":{"get":{"tags":["ZHZN agent releases"],"summary":"This cabinet's agent version and pin","operationId":"machine_agent_api_v1_machines__machine_no__agent_get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machine_no}/agent/pin":{"post":{"tags":["ZHZN agent releases"],"summary":"Hold a cabinet at an agent version","description":"Exempt one cabinet from the fleet rollout, in either direction.\n\nPinning below what the cabinet runs is the deliberate rollback: the health\ncheck reverts a version that will not start, and this reverts one that\nstarts fine and behaves badly, which no automatic check can detect.","operationId":"pin_machine_api_v1_machines__machine_no__agent_pin_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"delete":{"tags":["ZHZN agent releases"],"summary":"Release a cabinet's version pin","operationId":"unpin_machine_api_v1_machines__machine_no__agent_pin_delete","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/alerts/quiet-machines":{"get":{"tags":["Fleet alerts"],"summary":"Machines that have gone quiet, worst first","description":"Online machines selling nothing, judged against their own normal rhythm.\n\nTwo lists: `alerts` for gaps past what the machine normally does, ranked by\nseverity then overshoot, and `quiet` for a day or two of silence that is still\nwithin its rhythm. The split keeps the alert list worth reading.\n\nRender from `reason` (`never_sold` · `quiet_beyond_baseline` ·\n`quiet_no_baseline` · `within_baseline`), `severity`, `gapHours` and\n`baselineHours`. **`detail`, `gapLabel` and `baselineLabel` are English-only\nand deprecated for display** — they are kept for existing consumers, but a\nclient that prints them can never be translated.","operationId":"quiet_machines_api_v1_alerts_quiet_machines_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/alerts/unhosted-machines":{"get":{"tags":["Fleet alerts"],"summary":"Machines selling with no host linked, biggest first","description":"Sales that rang up with nobody to pay a commission to.\n\nA machine earns its host money only through a CRM venue that lists its\nserial. Placing a cabinet — setting its address and dropping its pin — does\nnot create that link, so a machine can sell for months while its host's\nstatement stays empty and no error is ever raised. This is that error,\nraised late but raised.\n\nThree lists. `gaps` is delivered vends no venue accrual window covers, each\nwith the takings behind it: `no_venue_linked` when nothing lists the serial,\n`sales_before_link` when a venue exists but those vends predate its accrual\nwindow (a host linked after the fact). `unlinked` is machines with no venue\nthat have not sold yet — worth closing before the first vend, not worth an\nalarm.\n\n`zeroRate` (`linked_at_zero`) is the third and least visible mistake: a venue\nlists the serial, inside its window, and its deal pays the host nothing.\n`POST /crm/venues` defaults to `net_revenue` at 0 bps and returns 200, so a\nhost signed up at nothing looks identical to a host signed up properly, and\nevery other coverage check reports them as covered. These takings are NOT\nadded to `unattributedGrossCents` — the machine is attributed, the deal is\nempty — so the row carries the gross behind the empty deal instead. A\nflat-rent or per-vend deal, or a 0% share with a monthly floor, is a real\ncontract and is not listed.\n\nFigures are **gross takings, not commission**: no rate exists for a machine\nwith no deal, and inventing one would be a number an operator could act on\nand should not. Nothing here back-dates anything; see\n`app/host_coverage.py` for why flagging beats retro-accrual.\n\nMachines an operator has declared host-free (`hostArrangement: \"none\"` on\nthe machine) appear on neither list and are counted in\n`counts.noHostDeclared`.","operationId":"unhosted_machines_api_v1_alerts_unhosted_machines_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/alerts/activity":{"get":{"tags":["Fleet alerts"],"summary":"Newest sales across the fleet","description":"Delivered sales, newest first, labelled by site.","operationId":"activity_api_v1_alerts_activity_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":12,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machine-iq/machines/{machineNo}/insights":{"get":{"tags":["Machine IQ"],"summary":"Ranked, citation-backed insights for one machine","description":"What's doing well on THIS machine, what to change, and how to maximize\ntotal revenue across every stream. Every insight carries citations into\nthe machine's fact table (returned alongside); the grounding validator\nguarantees nothing uncited ships. Thin data yields explicit data-gap\ndisclosures, never guesses.","operationId":"insights_api_v1_machine_iq_machines__machineNo__insights_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"Trailing window in days","default":28,"title":"Days"},"description":"Trailing window in days"},{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (dayparts)","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (dayparts)"},{"name":"deterministic","in":"query","required":false,"schema":{"type":"boolean","description":"Skip LLM phrasing (evals/CI)","default":false,"title":"Deterministic"},"description":"Skip LLM phrasing (evals/CI)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machine-iq/machines/{machineNo}/graph":{"get":{"tags":["Machine IQ"],"summary":"The machine's knowledge graph (machine-kg/v1, inspectable)","description":"Full deterministic graph export — nodes, edges, counts — so every\ninsight's graphPath can be walked by a human or a test.","operationId":"graph_api_v1_machine_iq_machines__machineNo__graph_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"Trailing window in days","default":28,"title":"Days"},"description":"Trailing window in days"},{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (dayparts)","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (dayparts)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machine-iq/machines/{machineNo}/facts":{"get":{"tags":["Machine IQ"],"summary":"The fact table — the only citable objects","operationId":"facts_api_v1_machine_iq_machines__machineNo__facts_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"Trailing window in days","default":28,"title":"Days"},"description":"Trailing window in days"},{"name":"tzOffsetMinutes","in":"query","required":false,"schema":{"type":"integer","maximum":840,"minimum":-840,"description":"Client UTC offset in minutes (dayparts)","default":0,"title":"Tzoffsetminutes"},"description":"Client UTC offset in minutes (dayparts)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/transfers/recipients":{"get":{"tags":["Ownership Transfers"],"summary":"Search operators to transfer to (typeahead)","description":"Prefix-match operator accounts by username (email local part) or\ndisplay name, or confirm an exact email. Excludes yourself and system\naccounts. Anti-harvesting: 3+ characters before anything matches, emails\ncome back masked unless the query IS the full email, and searches are\nbudgeted per caller (429 beyond the budget). Pass the returned\n``recipientId`` to initiate.","operationId":"search_recipients_api_v1_transfers_recipients_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Email, username, or display-name prefix","title":"Q"},"description":"Email, username, or display-name prefix"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/transfers/eligibility":{"get":{"tags":["Ownership Transfers"],"summary":"Which of my machines can transfer (and why not)","description":"Every machine you own with its transfer eligibility. Ineligible\nmachines carry the reason so pickers can show them disabled instead of\nhiding them.","operationId":"eligibility_api_v1_transfers_eligibility_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/transfers":{"post":{"tags":["Ownership Transfers"],"summary":"Initiate a machine ownership transfer","description":"Offer one or more of YOUR machines to another operator. All-or-nothing\nvalidation; one pending transfer record per machine. The machine stays\nfully yours and operational until the recipient accepts. Offers expire\nafter 7 days and are cancellable. Requires machines:write.","operationId":"initiate_transfer_api_v1_transfers_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateTransferRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"get":{"tags":["Ownership Transfers"],"summary":"List my transfers (incoming + outgoing)","description":"Transfers you initiated or were offered, newest first. Full-admin\nkeys see every operator's transfers; other principals need an operator\nidentity.","operationId":"list_transfers_api_v1_transfers_get","parameters":[{"name":"role","in":"query","required":false,"schema":{"type":"string","description":"all | incoming | outgoing","default":"all","title":"Role"},"description":"all | incoming | outgoing"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"pending | completed | declined | cancelled | expired","title":"Status"},"description":"pending | completed | declined | cancelled | expired"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/transfers/{transferId}":{"get":{"tags":["Ownership Transfers"],"summary":"Get one transfer","description":"Full transfer record including the event trail and (once completed)\nthe cut-over snapshot. Visible only to the two parties (and admin).","operationId":"get_transfer_api_v1_transfers__transferId__get","parameters":[{"name":"transferId","in":"path","required":true,"schema":{"type":"string","title":"Transferid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/transfers/{transferId}/accept":{"post":{"tags":["Ownership Transfers"],"summary":"Accept an incoming transfer (atomic cut-over)","description":"Recipient-only. Requires ``acknowledge=true`` (the audited in-app\ndouble-confirm). On success the ownership cut-over has already happened\natomically: tenant scoping, Nayax settlement, revenue attribution\ntimestamp, subscription detach + protection cancellation on the old\nowner, a fresh protection offer + billing checkpoint for you.","operationId":"accept_transfer_api_v1_transfers__transferId__accept_post","parameters":[{"name":"transferId","in":"path","required":true,"schema":{"type":"string","title":"Transferid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptTransferRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/transfers/{transferId}/decline":{"post":{"tags":["Ownership Transfers"],"summary":"Decline an incoming transfer","description":"Recipient-only. The machine never leaves the initiator's fleet.","operationId":"decline_transfer_api_v1_transfers__transferId__decline_post","parameters":[{"name":"transferId","in":"path","required":true,"schema":{"type":"string","title":"Transferid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeclineTransferRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/transfers/{transferId}/cancel":{"post":{"tags":["Ownership Transfers"],"summary":"Cancel a transfer I initiated","description":"Initiator-only (admin may also withdraw on an operator's behalf —\nwithdrawing an offer is not consenting to one).","operationId":"cancel_transfer_api_v1_transfers__transferId__cancel_post","parameters":[{"name":"transferId","in":"path","required":true,"schema":{"type":"string","title":"Transferid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/ideas":{"get":{"tags":["Operator workspace"],"summary":"Idea backlog with pipeline value","operationId":"list_ideas_api_v1_workspace_ideas_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator workspace"],"summary":"Capture an idea","operationId":"create_idea_api_v1_workspace_ideas_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdeaIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/ideas/{idea_id}":{"patch":{"tags":["Operator workspace"],"summary":"Patch Idea","operationId":"patch_idea_api_v1_workspace_ideas__idea_id__patch","parameters":[{"name":"idea_id","in":"path","required":true,"schema":{"type":"string","title":"Idea Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/ideas/{idea_id}/vote":{"post":{"tags":["Operator workspace"],"summary":"Upvote an idea","operationId":"vote_idea_api_v1_workspace_ideas__idea_id__vote_post","parameters":[{"name":"idea_id","in":"path","required":true,"schema":{"type":"string","title":"Idea Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/ideas/{idea_id}/promote":{"post":{"tags":["Operator workspace"],"summary":"Promote an idea into a real task","description":"Commit to an idea: creates a row in the Tasks board and links the two.\n\nThe task is the commitment; the idea keeps the thinking behind it. Nothing\nis duplicated, so closing the task does not leave a stale idea claiming to\nbe in progress.","operationId":"promote_idea_api_v1_workspace_ideas__idea_id__promote_post","parameters":[{"name":"idea_id","in":"path","required":true,"schema":{"type":"string","title":"Idea Id"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteIn","default":{"dueOn":"","notes":""}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/calendar":{"get":{"tags":["Operator workspace"],"summary":"Everything dated in the product, in one feed","description":"Task due dates, host payout runs, tax filing deadlines, contract\nrenewals and expiries, payroll periods, machine go-lives, SOP reviews and\nstandalone operator events — aggregated from the modules that own them.\n\nPass ``month`` for the month view or ``from``/``to`` for a week.","operationId":"calendar_api_v1_workspace_calendar_get","parameters":[{"name":"month","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"YYYY-MM; sets from/to","title":"Month"},"description":"YYYY-MM; sets from/to"},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/events":{"get":{"tags":["Operator workspace"],"summary":"Standalone operator events","operationId":"list_events_api_v1_workspace_events_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator workspace"],"summary":"Add a visit, restock run or meeting","operationId":"create_event_api_v1_workspace_events_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_workspace__EventIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/events/{event_id}":{"patch":{"tags":["Operator workspace"],"summary":"Patch Event","operationId":"patch_event_api_v1_workspace_events__event_id__patch","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/team":{"get":{"tags":["Operator workspace"],"summary":"Staff with their payroll rollup","description":"Each member's rate, hours and earnings come from the payroll module —\nthe team list is the identity layer over it, not a second copy.","operationId":"team_api_v1_workspace_team_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator workspace"],"summary":"Add a team member (creates their payroll identity)","operationId":"create_member_api_v1_workspace_team_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/team/{member_id}":{"patch":{"tags":["Operator workspace"],"summary":"Patch Member","operationId":"patch_member_api_v1_workspace_team__member_id__patch","parameters":[{"name":"member_id","in":"path","required":true,"schema":{"type":"string","title":"Member Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/team/{member_id}/hours":{"post":{"tags":["Operator workspace"],"summary":"Log a shift against a real member","operationId":"log_hours_api_v1_workspace_team__member_id__hours_post","parameters":[{"name":"member_id","in":"path","required":true,"schema":{"type":"string","title":"Member Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberHoursIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sops":{"get":{"tags":["Operator workspace"],"summary":"Procedures with acknowledgement coverage","operationId":"list_sops_api_v1_workspace_sops_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator workspace"],"summary":"Publish a procedure","operationId":"create_sop_api_v1_workspace_sops_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SopIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sops/{sop_id}":{"patch":{"tags":["Operator workspace"],"summary":"Edit a procedure (bumps the version)","description":"A change to the title, summary or steps publishes a new version, which\nresets acknowledgement coverage — the old signatures were for the old text.","operationId":"patch_sop_api_v1_workspace_sops__sop_id__patch","parameters":[{"name":"sop_id","in":"path","required":true,"schema":{"type":"string","title":"Sop Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sops/{sop_id}/ack":{"post":{"tags":["Operator workspace"],"summary":"Record that a team member has read it","operationId":"ack_sop_api_v1_workspace_sops__sop_id__ack_post","parameters":[{"name":"sop_id","in":"path","required":true,"schema":{"type":"string","title":"Sop Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AckIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sensitives":{"get":{"tags":["Operator workspace"],"summary":"Door/alarm codes and keys — masked","description":"Values are masked server-side; the plaintext only ever leaves through\n``POST /sensitives/{id}/reveal``, which writes an access-trail row.","operationId":"list_sensitives_api_v1_workspace_sensitives_get","parameters":[{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Operator workspace"],"summary":"Store a sensitive operational record","operationId":"create_sensitive_api_v1_workspace_sensitives_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sensitives/{sensitive_id}":{"patch":{"tags":["Operator workspace"],"summary":"Patch Sensitive","operationId":"patch_sensitive_api_v1_workspace_sensitives__sensitive_id__patch","parameters":[{"name":"sensitive_id","in":"path","required":true,"schema":{"type":"string","title":"Sensitive Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sensitives/{sensitive_id}/reveal":{"post":{"tags":["Operator workspace"],"summary":"Reveal one value (logged to the access trail)","operationId":"reveal_sensitive_api_v1_workspace_sensitives__sensitive_id__reveal_post","parameters":[{"name":"sensitive_id","in":"path","required":true,"schema":{"type":"string","title":"Sensitive Id"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__routes__operator_workspace__RevealIn","default":{"reason":""}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sensitives/encrypt-legacy":{"post":{"tags":["Operator workspace"],"summary":"Encrypt records stored before encryption at rest existed","description":"Seal any of your own sensitive values that are still stored in plaintext.\n\nOwner-only, like every other write here: a platform admin cannot read these\nvalues, so it would make no sense for one to be able to re-write them.\nIdempotent, and it never destroys a record it could not seal — a row that\nrefuses stays readable and is reported back so it can be retried.","operationId":"encrypt_legacy_sensitives_api_v1_workspace_sensitives_encrypt_legacy_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/workspace/sensitives/access":{"get":{"tags":["Operator workspace"],"summary":"Who accessed which sensitive record","operationId":"access_trail_api_v1_workspace_sensitives_access_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"operatorEmail","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials.","title":"Operatoremail"},"description":"Full admins only: scope this read to one operator. Omit to see every operator. Ignored for operator credentials."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/meta/state-machines":{"get":{"tags":["State-machine meta"],"summary":"Every state machine, generated from the code","description":"Machine lifecycle, DFY deal stages, protection plan and claim\nmachines as JSON graph specs + Mermaid, derived from the live\ntransition tables/functions at request time (never hand-drawn, can't\ndrift). Requires machines:read.","operationId":"state_machines_api_v1_meta_state_machines_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/meta/state-machines/{name}":{"get":{"tags":["State-machine meta"],"summary":"One state machine spec by name","operationId":"state_machine_api_v1_meta_state_machines__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/dfy/deals/{dealId}/replay":{"get":{"tags":["Replay"],"summary":"Step replay of a deal's timeline","description":"The ordered event stream folded into per-step state snapshots\n(stage, negotiation standing offer/envelope, lease/order status,\ncheckpoint states), with per-step diffs and honest ``approximate``\nmarking where old records lack replay data. Requires machines:read.","operationId":"deal_replay_api_v1_dfy_deals__dealId__replay_get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/machines/{machineNo}/lifecycle/replay":{"get":{"tags":["Replay"],"summary":"Step replay of a machine's lifecycle trail","operationId":"machine_replay_api_v1_machines__machineNo__lifecycle_replay_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/state-machines":{"get":{"tags":["Super-admin observability"],"summary":"Generated graphs + live per-state counts","operationId":"sa_state_machines_api_v1_superadmin_state_machines_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/replay/deals":{"get":{"tags":["Super-admin observability"],"summary":"Replayable deals","operationId":"sa_replay_deals_api_v1_superadmin_replay_deals_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/replay/deals/{dealId}":{"get":{"tags":["Super-admin observability"],"summary":"Step replay of any deal","operationId":"sa_replay_deal_api_v1_superadmin_replay_deals__dealId__get","parameters":[{"name":"dealId","in":"path","required":true,"schema":{"type":"string","title":"Dealid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/replay/machines":{"get":{"tags":["Super-admin observability"],"summary":"Replayable machines","operationId":"sa_replay_machines_api_v1_superadmin_replay_machines_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/superadmin/replay/machines/{machineNo}":{"get":{"tags":["Super-admin observability"],"summary":"Step replay of any machine's lifecycle","operationId":"sa_replay_machine_api_v1_superadmin_replay_machines__machineNo__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/v2/{path}":{"head":{"summary":"Nakama V2 Proxy","operationId":"nakama_v2_proxy_v2__path__head","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Nakama V2 Proxy","operationId":"nakama_v2_proxy_v2__path__head","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Nakama V2 Proxy","operationId":"nakama_v2_proxy_v2__path__head","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Nakama V2 Proxy","operationId":"nakama_v2_proxy_v2__path__head","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Nakama V2 Proxy","operationId":"nakama_v2_proxy_v2__path__head","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Nakama V2 Proxy","operationId":"nakama_v2_proxy_v2__path__head","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"options":{"summary":"Nakama V2 Proxy","operationId":"nakama_v2_proxy_v2__path__head","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/arcade-lan":{"get":{"summary":"Get Arcade Lan","description":"Laptop demo: bounce localhost → the Wi-Fi address phones can scan.","operationId":"get_arcade_lan_api_arcade_lan_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/kiosk-match":{"get":{"summary":"Get Kiosk Match","operationId":"get_kiosk_match_api_kiosk_match_get","parameters":[{"name":"game","in":"query","required":false,"schema":{"type":"string","default":"golfx","title":"Game"}},{"name":"machineNo","in":"query","required":false,"schema":{"type":"string","default":"","title":"Machineno"}},{"name":"matchId","in":"query","required":false,"schema":{"type":"string","default":"","title":"Matchid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Post Kiosk Match","operationId":"post_kiosk_match_api_kiosk_match_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-rewards/claim":{"post":{"summary":"Post Arcade Reward Claim","description":"Phone/glass claims a scarce wallet payout. Amount is server-side.","operationId":"post_arcade_reward_claim_api_arcade_rewards_claim_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-ads/config":{"get":{"summary":"Get Arcade Ads Config","description":"Public H5 ad knobs for the TV game WebView. Empty ca-pub = ads off.\n\nca-pub / AdMob slots are publisher-facing ids, not secrets. Attract\n``/apk/getAd`` is unchanged.","operationId":"get_arcade_ads_config_api_arcade_ads_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-ads/house":{"get":{"summary":"Get Arcade Ads House","description":"One web-safe attract creative for TIME'S UP when Google H5 is off.\n\nSame loop as ``/apk/getAd`` / ``/kiosk/api/ads`` — never Google H5,\nAdSense, or AdMob. Empty inventory still returns a 5-second house card\nso the Watch button is never a dead end.","operationId":"get_arcade_ads_house_api_arcade_ads_house_get","parameters":[{"name":"machineNo","in":"query","required":false,"schema":{"type":"string","default":"","title":"Machineno"}},{"name":"machineId","in":"query","required":false,"schema":{"type":"string","default":"","title":"Machineid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/arcade-ads/catalog-break":{"post":{"summary":"Post Arcade Ads Catalog Break","description":"One browse interstitial per cabinet visit. Never play time, never coins.","operationId":"post_arcade_ads_catalog_break_api_arcade_ads_catalog_break_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-session/status":{"get":{"summary":"Get Arcade Session","operationId":"get_arcade_session_api_arcade_session_status_get","parameters":[{"name":"game","in":"query","required":false,"schema":{"type":"string","default":"golfx","title":"Game"}},{"name":"machineNo","in":"query","required":false,"schema":{"type":"string","default":"","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/arcade-session/start":{"post":{"summary":"Post Arcade Session Start","operationId":"post_arcade_session_start_api_arcade_session_start_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-session/leave":{"post":{"summary":"Post Arcade Session Leave","description":"Back to Shop / close title. Drops unpaid leftover TIME'S UP. Never vends.","operationId":"post_arcade_session_leave_api_arcade_session_leave_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-session/breadcrumb":{"post":{"summary":"Post Arcade Session Breadcrumb","description":"Funnel crumbs (boot/error/quit/round_end). Never blocks play, never vends.","operationId":"post_arcade_session_breadcrumb_api_arcade_session_breadcrumb_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-session/continue":{"post":{"summary":"Post Arcade Session Continue","operationId":"post_arcade_session_continue_api_arcade_session_continue_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-session/continue-ad":{"post":{"summary":"Post Arcade Session Continue Ad","description":"Watch-ad continue: 5 minutes, no coins, no vend. Body matches paid continue.","operationId":"post_arcade_session_continue_ad_api_arcade_session_continue_ad_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/arcade-session/pay/{session_id}":{"get":{"summary":"Arcade Session Pay Page","description":"Sandbox continue page when no hosted rail is live. Never vends.","operationId":"arcade_session_pay_page_api_arcade_session_pay__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/arcade-session/pay/{session_id}/simulate":{"post":{"summary":"Arcade Session Simulate Pay","operationId":"arcade_session_simulate_pay_api_arcade_session_pay__session_id__simulate_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/arcade-session/paid":{"get":{"summary":"Arcade Session Paid Redirect","operationId":"arcade_session_paid_redirect_api_arcade_session_paid_get","parameters":[{"name":"sid","in":"query","required":false,"schema":{"type":"string","default":"","title":"Sid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/g/{game}/{match_id}/qr.png":{"get":{"summary":"Arcade Join Qr","description":"Branded join QR — same renderer as photobooth / fortune / merch.\n\nThe glass shows this PNG only. The join URL stays inside the code,\nnever as text under the tile.","operationId":"arcade_join_qr_g__game___match_id__qr_png_get","parameters":[{"name":"game","in":"path","required":true,"schema":{"type":"string","title":"Game"}},{"name":"match_id","in":"path","required":true,"schema":{"type":"string","title":"Match Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/g/{game}/{match_id}":{"get":{"summary":"Arcade Join Page","description":"Phone QR target. Serve the controller here — no 302.\n\niOS Camera and free ngrok drop or refuse redirects that carry\n``?query`` or ``#hash``. The match id stays in the path; a <base>\ntag makes ``../../src/kiosk-x-sdk.js`` resolve under /web-games.","operationId":"arcade_join_page_g__game___match_id__get","parameters":[{"name":"game","in":"path","required":true,"schema":{"type":"string","title":"Game"}},{"name":"match_id","in":"path","required":true,"schema":{"type":"string","title":"Match Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/kiosk-relay":{"get":{"summary":"Probe Kiosk Relay","operationId":"probe_kiosk_relay_api_kiosk_relay_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/machines/{machineNo}/experience":{"get":{"tags":["Screen experiences"],"summary":"Get Experience","operationId":"get_experience_api_v1_machines__machineNo__experience_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"put":{"tags":["Screen experiences"],"summary":"Put Experience","operationId":"put_experience_api_v1_machines__machineNo__experience_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/manufacturer":{"get":{"tags":["Manufacturer portal"],"summary":"Workspace","operationId":"workspace_api_v1_manufacturer_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/manufacturer/machines/{machine_no}":{"get":{"tags":["Manufacturer portal"],"summary":"Machine","operationId":"machine_api_v1_manufacturer_machines__machine_no__get","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/manufacturer/batches":{"post":{"tags":["Manufacturer portal"],"summary":"Save","operationId":"save_api_v1_manufacturer_batches_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/manufacturer/machines/{machine_no}/bench":{"post":{"tags":["Manufacturer portal"],"summary":"Bench","operationId":"bench_api_v1_manufacturer_machines__machine_no__bench_post","parameters":[{"name":"machine_no","in":"path","required":true,"schema":{"type":"string","title":"Machine No"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Bench"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/refill-photos":{"get":{"tags":["Refill photos"],"summary":"History","operationId":"history_api_v1_inventory_machines__machineNo__refill_photos_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]},"post":{"tags":["Refill photos"],"summary":"Upload","operationId":"upload_api_v1_inventory_machines__machineNo__refill_photos_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/refill-photos/{photoId}":{"get":{"tags":["Refill photos"],"summary":"Get Photo","operationId":"get_photo_api_v1_inventory_machines__machineNo__refill_photos__photoId__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"photoId","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Photoid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/refill-photos/{photoId}/analyze":{"post":{"tags":["Refill photos"],"summary":"Analyze","operationId":"analyze_api_v1_inventory_machines__machineNo__refill_photos__photoId__analyze_post","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"photoId","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Photoid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/refill-photos/{photoId}/review":{"put":{"tags":["Refill photos"],"summary":"Review","operationId":"review_api_v1_inventory_machines__machineNo__refill_photos__photoId__review_put","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"photoId","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Photoid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/refill-events":{"get":{"tags":["Refill photos"],"summary":"Events","operationId":"events_api_v1_inventory_machines__machineNo__refill_events_get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}},"/api/v1/inventory/machines/{machineNo}/refill-events/{eventId}":{"get":{"tags":["Refill photos"],"summary":"Event","operationId":"event_api_v1_inventory_machines__machineNo__refill_events__eventId__get","parameters":[{"name":"machineNo","in":"path","required":true,"schema":{"type":"string","title":"Machineno"}},{"name":"eventId","in":"path","required":true,"schema":{"type":"string","title":"Eventid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"X-API-Key":[]},{"OAuth2":[]}]}}},"components":{"schemas":{"AcceptIn":{"properties":{"note":{"type":"string","title":"Note","default":""},"condition":{"type":"string","title":"Condition","default":"good"}},"type":"object","title":"AcceptIn"},"AcceptTransferRequest":{"properties":{"acknowledge":{"type":"boolean","title":"Acknowledge","description":"Explicit double-confirm: you accept ownership, tenant scoping, and responsibility for the machine's base subscription going forward","default":false}},"type":"object","title":"AcceptTransferRequest"},"AckCommandRequest":{"properties":{"success":{"type":"boolean","title":"Success"},"outcome":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Outcome"},"detail":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Detail"}},"type":"object","required":["success"],"title":"AckCommandRequest"},"AckIn":{"properties":{"member":{"type":"string","title":"Member","description":"Team member id or email"},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["member"],"title":"AckIn"},"AcquisitionIn":{"properties":{"costUsd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Costusd"},"paidUsd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Paidusd"},"funding":{"type":"string","title":"Funding","description":"cash | credit | contributed","default":""},"acquiredOn":{"type":"string","title":"Acquiredon","default":""},"supplier":{"type":"string","title":"Supplier","default":""},"invoiceRef":{"type":"string","title":"Invoiceref","default":""},"inServiceOn":{"type":"string","title":"Inserviceon","description":"Overrides the derived in-service date. Left empty, depreciation starts from the machine's first venue placement — not from when it was manufactured.","default":""},"usefulLifeMonths":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Usefullifemonths"},"salvageUsd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Salvageusd"},"note":{"type":"string","title":"Note","default":""},"amendmentReason":{"type":"string","title":"Amendmentreason","description":"Why a cost already recorded is being changed. Restating an acquisition restates the depreciation, and therefore the profit, of every period since — so the change is kept on the record's amendment trail with this reason rather than overwriting silently.","default":""}},"additionalProperties":false,"type":"object","title":"AcquisitionIn","description":"What the operator paid for this cabinet, and how.\n\n``funding`` is the load-bearing field, because it decides what balances the\nasset on the operator's sheet: ``cash`` takes it out of cash, ``credit``\nraises accounts payable, and ``contributed`` books it against owner capital\n(the case for a fleet that predates Kiosk-X). Same ``exclude_unset``\ntreatment as ``BuildIn`` — correcting a supplier must not reset a life.\n\nUnknown fields are refused, not ignored — see ``_STRICT``."},"AdminPinBody":{"properties":{"pin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pin"},"rotate":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Rotate"}},"type":"object","title":"AdminPinBody"},"AgeVerificationPolicy":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":false},"minAge":{"type":"integer","maximum":99.0,"minimum":16.0,"title":"Minage","description":"Age threshold buyers must prove","default":21},"appliesTo":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":12},{"type":"null"}],"title":"Appliesto","description":"Product verticals in scope, or [\"all\"] (default)"},"failOpen":{"type":"boolean","title":"Failopen","description":"Proceed without verification when Didit is unreachable (default False = fail closed)","default":false}},"type":"object","title":"AgeVerificationPolicy","description":"Per-machine Didit identity/age verification gate (default OFF).\n\nWhen enabled, buyers must pass a phone identity verification (Didit\nhosted document + liveness, entered via QR) before a purchase can\ncomplete — Scan & Pay verifies inside the payment flow itself; the card\ntile requires the machine's verification QR first. ``appliesTo`` scopes\nthe gate to product verticals (aisle categories, e.g. [\"alcohol\",\n\"vape\"]) or [\"all\"]. ``failOpen`` default False = verification service\ndown blocks restricted sales (fail-closed)."},"AisleUpdateRequest":{"properties":{"currentStock":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Currentstock"},"maxStock":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Maxstock"},"sellingPrice":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Sellingprice"},"alertThreshold":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Alertthreshold"},"faulted":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Faulted"},"productName":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Productname"},"productCode":{"anyOf":[{"type":"string","maxLength":40,"minLength":1},{"type":"null"}],"title":"Productcode"},"productImageUrl":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Productimageurl"},"category":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Category"},"minAge":{"anyOf":[{"type":"integer","maximum":99.0,"minimum":0.0},{"type":"null"}],"title":"Minage"}},"additionalProperties":true,"type":"object","title":"AisleUpdateRequest"},"AnnounceBody":{"properties":{"text":{"type":"string","maxLength":280,"minLength":1,"title":"Text"},"volume":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Volume"}},"type":"object","required":["text"],"title":"AnnounceBody"},"ApproveCandidatesRequest":{"properties":{"candidateIds":{"items":{"type":"string"},"type":"array","title":"Candidateids"},"autoOutreach":{"type":"boolean","title":"Autooutreach","default":false}},"type":"object","required":["candidateIds"],"title":"ApproveCandidatesRequest"},"ApproveOrderRequest":{"properties":{"approve":{"type":"boolean","title":"Approve","default":true},"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","title":"ApproveOrderRequest"},"ApproveTermsRequest":{"properties":{"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","title":"ApproveTermsRequest"},"ArchiveRequest":{"properties":{"documentId":{"type":"integer","title":"Documentid"},"kind":{"type":"string","title":"Kind"},"ref":{"type":"string","title":"Ref"}},"type":"object","required":["documentId","kind","ref"],"title":"ArchiveRequest"},"Batch":{"properties":{"batchId":{"type":"string","maxLength":80,"minLength":1,"pattern":"^[A-Za-z0-9_-]+$","title":"Batchid"},"manufacturer":{"type":"string","maxLength":60,"minLength":2,"pattern":"^[a-z0-9][a-z0-9_-]+$","title":"Manufacturer"},"machineNos":{"items":{"type":"string"},"type":"array","maxItems":100,"minItems":1,"title":"Machinenos"},"status":{"type":"string","enum":["draft","dispatched"],"title":"Status","default":"draft"},"version":{"type":"integer","minimum":0.0,"title":"Version","default":0},"carrier":{"type":"string","maxLength":120,"title":"Carrier","default":""},"trackingNumber":{"type":"string","maxLength":160,"title":"Trackingnumber","default":""},"containerNumber":{"type":"string","maxLength":100,"title":"Containernumber","default":""},"departureDate":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Departuredate"},"etaDate":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Etadate"},"destination":{"type":"string","maxLength":500,"title":"Destination","default":""},"notes":{"type":"string","maxLength":2000,"title":"Notes","default":""}},"additionalProperties":false,"type":"object","required":["batchId","manufacturer","machineNos"],"title":"Batch"},"Bench":{"properties":{"action":{"type":"string","enum":["test","sign"],"title":"Action"},"requestId":{"type":"string","maxLength":80,"minLength":8,"title":"Requestid"},"version":{"type":"integer","minimum":0.0,"title":"Version"},"manufacturer":{"type":"string","maxLength":60,"title":"Manufacturer","default":""},"code":{"type":"string","maxLength":30,"title":"Code","default":""},"result":{"type":"string","maxLength":20,"title":"Result","default":"skip"},"detail":{"type":"string","maxLength":2000,"minLength":5,"title":"Detail"},"technician":{"type":"string","maxLength":120,"minLength":2,"title":"Technician"},"observed":{"type":"boolean","title":"Observed"}},"additionalProperties":false,"type":"object","required":["action","requestId","version","detail","technician","observed"],"title":"Bench"},"Body_token_oauth_token_post":{"properties":{"grant_type":{"type":"string","title":"Grant Type"},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"}},"type":"object","required":["grant_type"],"title":"Body_token_oauth_token_post"},"BriefingViewedRequest":{"properties":{"tzOffsetMinutes":{"type":"integer","maximum":840.0,"minimum":-840.0,"title":"Tzoffsetminutes","default":0},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone","description":"IANA zone; preferred over the offset"},"completed":{"type":"boolean","title":"Completed","description":"False = dismissed before the last card","default":true},"firstCardTapped":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstcardtapped","description":"Card id the operator tapped first — feeds the learned order"}},"type":"object","title":"BriefingViewedRequest"},"BuildIn":{"properties":{"manufacturer":{"type":"string","title":"Manufacturer","default":""},"model":{"type":"string","title":"Model","default":""},"orderRef":{"type":"string","title":"Orderref","default":""},"batchRef":{"type":"string","title":"Batchref","default":""},"boardRevision":{"type":"string","title":"Boardrevision","default":""},"factory":{"type":"string","title":"Factory","default":""},"builtAt":{"type":"string","title":"Builtat","default":""},"shippedAt":{"type":"string","title":"Shippedat","default":""},"shippedFirmware":{"anyOf":[{"$ref":"#/components/schemas/FirmwareIn"},{"type":"null"}]},"shipping":{"anyOf":[{"$ref":"#/components/schemas/ShippingIn"},{"type":"null"}]},"acquisition":{"anyOf":[{"$ref":"#/components/schemas/AcquisitionIn"},{"type":"null"}]}},"additionalProperties":false,"type":"object","title":"BuildIn","description":"Every field is optional, and only the ones actually sent are written.\n\nA manufacturer webhook reporting a ship date must not blank the board\nrevision it had nothing to say about, so this is dumped with\n``exclude_unset`` — with plain defaults, an absent field and a field\nexplicitly cleared are indistinguishable.\n\nWhich is exactly why unknown fields are refused rather than ignored — see\n``_STRICT``. ``exclude_unset`` means a misspelt field is not merely dropped,\nit is indistinguishable from one the caller never mentioned."},"BulkControlBody":{"properties":{"machineNos":{"items":{"type":"string"},"type":"array","title":"Machinenos"},"catalog":{"anyOf":[{"$ref":"#/components/schemas/CatalogBody"},{"type":"null"}]},"gameEnabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Gameenabled"},"prizes":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Prizes"}},"type":"object","required":["machineNos"],"title":"BulkControlBody"},"CameraLiveBody":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"seconds":{"type":"integer","maximum":300.0,"minimum":5.0,"title":"Seconds","default":60},"interval":{"type":"integer","maximum":30.0,"minimum":1.0,"title":"Interval","default":1}},"type":"object","title":"CameraLiveBody"},"CampaignCreateRequest":{"properties":{"name":{"type":"string","title":"Name","examples":["Joe's Pizza — 2 Slices $5"]},"sponsorName":{"type":"string","title":"Sponsorname","examples":["Joe's Pizza (Main Street)"]},"sponsorType":{"type":"string","title":"Sponsortype","description":"local-business | stocked-brand-coop | house","default":"local-business"},"creative":{"anyOf":[{"$ref":"#/components/schemas/CreativeModel"},{"type":"null"}]},"flightStart":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flightstart","description":"ISO timestamp; defaults to now"},"flightEnd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flightend","description":"ISO timestamp; defaults to +30 days"},"targetMachines":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}],"title":"Targetmachines","description":"'all' or explicit machineNo list (ignored when targetGeo is set)","default":"all"},"targetGeo":{"anyOf":[{"$ref":"#/components/schemas/GeoTargetModel"},{"type":"null"}],"description":"Geo spec — overrides targetMachines; resolved at flight time"},"weight":{"type":"integer","maximum":8.0,"minimum":1.0,"title":"Weight","description":"Loop slots per rotation this sponsor bought","default":1},"pricing":{"anyOf":[{"$ref":"#/components/schemas/PricingModel"},{"type":"null"}]}},"type":"object","required":["name","sponsorName"],"title":"CampaignCreateRequest"},"CampaignUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"sponsorName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sponsorname"},"sponsorType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sponsortype"},"creative":{"anyOf":[{"$ref":"#/components/schemas/CreativeModel"},{"type":"null"}]},"flightStart":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flightstart"},"flightEnd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flightend"},"targetMachines":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Targetmachines"},"targetGeo":{"anyOf":[{"$ref":"#/components/schemas/GeoTargetModel"},{"type":"null"}]},"weight":{"anyOf":[{"type":"integer","maximum":8.0,"minimum":1.0},{"type":"null"}],"title":"Weight"},"pricing":{"anyOf":[{"$ref":"#/components/schemas/PricingModel"},{"type":"null"}]}},"type":"object","title":"CampaignUpdateRequest"},"CancelRequest":{"properties":{"reason":{"type":"string","title":"Reason","default":"operator cancelled"}},"type":"object","title":"CancelRequest"},"CardVerify":{"properties":{"card":{"type":"object","title":"Card","description":"The [opxcard] payload as received"}},"type":"object","required":["card"],"title":"CardVerify"},"CatalogBody":{"properties":{"titles":{"items":{"type":"string"},"type":"array","title":"Titles"},"featured":{"type":"string","title":"Featured"}},"type":"object","required":["titles","featured"],"title":"CatalogBody"},"ChangeIn":{"properties":{"ticket":{"type":"string","title":"Ticket"},"ssid":{"type":"string","title":"Ssid"},"passphrase":{"type":"string","title":"Passphrase","default":""},"security":{"type":"string","title":"Security","default":"wpa2"}},"type":"object","required":["ticket","ssid"],"title":"ChangeIn"},"ChangePasswordRequest":{"properties":{"oldPassword":{"type":"string","title":"Oldpassword"},"newPassword":{"type":"string","title":"Newpassword"},"confirmPassword":{"type":"string","title":"Confirmpassword"}},"type":"object","required":["oldPassword","newPassword","confirmPassword"],"title":"ChangePasswordRequest"},"ChatRequest":{"properties":{"message":{"type":"string","maxLength":4000,"minLength":1,"title":"Message","examples":["Which machines are low on stock?"]},"history":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"History","description":"Prior visible turns, oldest first: {role: user|assistant, content: str}"},"page":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Page","description":"Console page the operator is on, e.g. /ads"},"tzOffsetMinutes":{"anyOf":[{"type":"integer","maximum":840.0,"minimum":-840.0},{"type":"null"}],"title":"Tzoffsetminutes","description":"Client UTC offset (JS: -new Date().getTimezoneOffset())"}},"type":"object","required":["message"],"title":"ChatRequest"},"CheckRequest":{"properties":{"address":{"$ref":"#/components/schemas/StructuredAddress"},"expectedFingerprint":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Expectedfingerprint"}},"additionalProperties":false,"type":"object","required":["address","expectedFingerprint"],"title":"CheckRequest"},"ClaimAdvanceRequest":{"properties":{"status":{"type":"string","enum":["approved","in_repair","resolved","denied"],"title":"Status"},"resolution":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}],"title":"Resolution"}},"type":"object","required":["status"],"title":"ClaimAdvanceRequest"},"ClaimOpenRequest":{"properties":{"kind":{"type":"string","enum":["malfunction","damage","vandalism","theft","other"],"title":"Kind"},"description":{"type":"string","maxLength":600,"minLength":5,"title":"Description"}},"type":"object","required":["kind","description"],"title":"ClaimOpenRequest"},"CodeBody":{"properties":{"mfaTicket":{"type":"string","minLength":8,"title":"Mfaticket"},"code":{"type":"string","maxLength":16,"minLength":6,"title":"Code"}},"type":"object","required":["mfaTicket","code"],"title":"CodeBody"},"CompleteInstallRequest":{"properties":{"force":{"type":"boolean","title":"Force","default":false}},"type":"object","title":"CompleteInstallRequest"},"ConciergeRequest":{"properties":{"action":{"type":"string","title":"Action"},"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","required":["action"],"title":"ConciergeRequest"},"ConfigRequest":{"properties":{"geoGateRadiusM":{"anyOf":[{"type":"number","maximum":5000.0,"minimum":25.0},{"type":"null"}],"title":"Geogateradiusm"},"rewardDailyBudgetUsd":{"anyOf":[{"type":"number","maximum":500.0,"minimum":0.0},{"type":"null"}],"title":"Rewarddailybudgetusd"},"rewardMaxPerPlayerPerDay":{"anyOf":[{"type":"integer","maximum":10.0,"minimum":1.0},{"type":"null"}],"title":"Rewardmaxperplayerperday"},"rewardUsdByKind":{"anyOf":[{"additionalProperties":{"type":"number"},"type":"object"},{"type":"null"}],"title":"Rewardusdbykind"},"churnDays":{"anyOf":[{"type":"integer","maximum":90.0,"minimum":3.0},{"type":"null"}],"title":"Churndays"},"restrictedVerticalGating":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Restrictedverticalgating"},"pushEnabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Pushenabled"},"roles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Roles"},"retentionContacts":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Retentioncontacts"},"agentsDisabled":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Agentsdisabled"},"fortuneMachines":{"anyOf":[{"additionalProperties":{"type":"object"},"type":"object"},{"type":"null"}],"title":"Fortunemachines"}},"type":"object","title":"ConfigRequest"},"ConfirmEnrollRequest":{"properties":{"totpCode":{"type":"string","title":"Totpcode"}},"type":"object","required":["totpCode"],"title":"ConfirmEnrollRequest"},"ConfirmRequest":{"properties":{"checkId":{"type":"string","maxLength":128,"minLength":16,"title":"Checkid"},"candidateId":{"type":"string","maxLength":128,"minLength":8,"title":"Candidateid"},"expectedFingerprint":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Expectedfingerprint"},"confirmed":{"type":"boolean","title":"Confirmed"}},"additionalProperties":false,"type":"object","required":["checkId","candidateId","expectedFingerprint","confirmed"],"title":"ConfirmRequest"},"ConsumeIn":{"properties":{"sku":{"type":"string","title":"Sku"},"qty":{"type":"number","title":"Qty"}},"type":"object","required":["sku","qty"],"title":"ConsumeIn"},"ContactRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"}},"type":"object","title":"ContactRequest"},"ContentxCreativeRequest":{"properties":{"brief":{"type":"string","minLength":8,"title":"Brief","examples":["Bold vertical digital-signage poster for Joe's Pizza: two pepperoni slices, '2 SLICES $5', warm lighting"]},"aspectRatio":{"type":"string","title":"Aspectratio","description":"Kiosk screens are 1080x1920 portrait","default":"9:16"},"mediaType":{"type":"string","title":"Mediatype","description":"Only 'image' is generated today; video briefs go through ContentX studio manually","default":"image"}},"type":"object","required":["brief"],"title":"ContentxCreativeRequest"},"CounterRequest":{"properties":{"message":{"type":"string","title":"Message"},"terms":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Terms"},"channel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel"}},"type":"object","required":["message"],"title":"CounterRequest"},"CreateAccountRequest":{"properties":{"email":{"type":"string","title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region"},"roleId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Roleid"},"roles":{"items":{"type":"string"},"type":"array","title":"Roles"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"}},"type":"object","required":["email"],"title":"CreateAccountRequest"},"CreateDealRequest":{"properties":{"title":{"type":"string","title":"Title"}},"type":"object","required":["title"],"title":"CreateDealRequest"},"CreativeModel":{"properties":{"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"image | video"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Hosted creative URL (S3 / ContentX asset)"},"durationSeconds":{"anyOf":[{"type":"integer","maximum":120.0,"minimum":1.0},{"type":"null"}],"title":"Durationseconds"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"contentx | upload | url"},"contentxRef":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contentxref","description":"ContentX asset/brief reference"}},"type":"object","title":"CreativeModel"},"CreativeUploadRequest":{"properties":{"contentType":{"type":"string","title":"Contenttype","description":"image/png | image/jpeg | image/webp | video/mp4"},"dataBase64":{"type":"string","title":"Database64","description":"The file, base64 (standard alphabet)"},"durationSeconds":{"anyOf":[{"type":"integer","maximum":120.0,"minimum":1.0},{"type":"null"}],"title":"Durationseconds"}},"type":"object","required":["contentType","dataBase64"],"title":"CreativeUploadRequest","description":"A poster or clip carried inline. JSON rather than multipart because the\nOperator X console reaches this API through a same-origin proxy that\nforwards request bodies as text (kiosk-x-operator ``app/api/vtm``)."},"CredentialActionIn":{"properties":{"reason":{"type":"string","title":"Reason","description":"Why — what makes you think this cabinet's key is in someone else's hands, or which planned rotation this is"}},"type":"object","required":["reason"],"title":"CredentialActionIn"},"CrewCreate":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"CrewCreate"},"CrewInvite":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"role":{"type":"string","title":"Role"}},"type":"object","required":["email","role"],"title":"CrewInvite"},"CrewMemberUpdate":{"properties":{"role":{"type":"string","title":"Role"}},"type":"object","required":["role"],"title":"CrewMemberUpdate"},"DealAutopilotRequest":{"properties":{"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"}},"type":"object","title":"DealAutopilotRequest"},"DealIn":{"properties":{"name":{"type":"string","title":"Name"},"stage":{"type":"string","title":"Stage","default":"shortlisting"},"dfyDealId":{"type":"string","title":"Dfydealid","default":""},"venueId":{"type":"string","title":"Venueid","default":""},"leadId":{"type":"string","title":"Leadid","default":""},"kioskMachineNo":{"type":"string","title":"Kioskmachineno","default":""},"expectedCloseOn":{"type":"string","title":"Expectedcloseon","default":""}},"additionalProperties":true,"type":"object","required":["name"],"title":"DealIn"},"DeclareBody":{"properties":{"variantId":{"type":"string","maxLength":120,"minLength":1,"title":"Variantid"},"promote":{"type":"boolean","title":"Promote","default":false}},"additionalProperties":false,"type":"object","required":["variantId"],"title":"DeclareBody"},"DeclineTransferRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Reason"}},"type":"object","title":"DeclineTransferRequest"},"DecommissionRequest":{"properties":{"proceedsUsd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Proceedsusd","description":"What you actually received for the cabinet, if anything: scrap value, an off-platform sale, a refund. Recorded as the proceeds on the fixed-asset disposal, so the gain or loss on your balance sheet is proceeds less net book value. Leave it out for a write-off — nothing is assumed, because inventing proceeds would overstate your profit. For a sale to another operator ON the platform use the transfer flow instead (POST /api/v1/transfers): the price is recorded once there and read by both sets of books."},"reason":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Reason"}},"type":"object","title":"DecommissionRequest","description":"Optional. A body-less POST still works, and books a full write-off."},"DeviceRequest":{"properties":{"token":{"type":"string","title":"Token"},"platform":{"type":"string","title":"Platform","description":"android | ios"}},"type":"object","required":["token","platform"],"title":"DeviceRequest"},"DispatchInstallRequest":{"properties":{"confirm":{"type":"boolean","title":"Confirm","default":false},"assignee":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assignee"}},"type":"object","title":"DispatchInstallRequest"},"DispenseCommandRequest":{"properties":{"aisleNo":{"type":"integer","maximum":200.0,"minimum":1.0,"title":"Aisleno"},"quantity":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Quantity","default":1},"reason":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Reason"},"externalRef":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Externalref"},"free":{"type":"boolean","title":"Free","default":false}},"type":"object","required":["aisleNo"],"title":"DispenseCommandRequest"},"DmSend":{"properties":{"toNakamaUserId":{"type":"string","maxLength":64,"minLength":8,"title":"Tonakamauserid"},"text":{"type":"string","maxLength":2000,"minLength":1,"title":"Text"}},"type":"object","required":["toNakamaUserId","text"],"title":"DmSend"},"EnrollRequest":{"properties":{"password":{"type":"string","title":"Password"}},"type":"object","required":["password"],"title":"EnrollRequest"},"EnrolmentArmIn":{"properties":{"reason":{"type":"string","title":"Reason","description":"Which install, RMA or bench run this is — the arm is the one thing that lets the shared fleet secret claim a cabinet, so an unattributed one is worthless"},"ttlMinutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttlminutes","description":"How long the window stays open. Defaults to 30 minutes; 24 hours is the maximum."},"deviceId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deviceid","description":"This unit's /etc/machine-id, if you are holding it. Pins the arm to one box so nobody else can spend the window."}},"type":"object","required":["reason"],"title":"EnrolmentArmIn"},"EnvelopeRequest":{"properties":{"revenueSharePct":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Revenuesharepct"},"termMonths":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Termmonths"},"powerPaidBy":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Powerpaidby"},"installWindowDays":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Installwindowdays"},"dealBreakers":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Dealbreakers"}},"type":"object","title":"EnvelopeRequest"},"EventsRequest":{"properties":{"events":{"items":{"$ref":"#/components/schemas/app__routes__engagement_metrics__EventIn"},"type":"array","maxItems":100,"title":"Events"}},"type":"object","required":["events"],"title":"EventsRequest"},"ExceptionRequest":{"properties":{"kind":{"type":"string","title":"Kind"},"operatorEmail":{"type":"string","title":"Operatoremail"},"summary":{"type":"string","title":"Summary"},"amountUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amountusd"},"ref":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Ref"}},"type":"object","required":["kind","operatorEmail","summary"],"title":"ExceptionRequest"},"ExpenseIn":{"properties":{"category":{"type":"string","title":"Category"},"usd":{"type":"number","title":"Usd"},"spentOn":{"type":"string","title":"Spenton","default":""},"vendor":{"type":"string","title":"Vendor","default":""},"machineNo":{"type":"string","title":"Machineno","default":""},"venueId":{"type":"string","title":"Venueid","default":""},"note":{"type":"string","title":"Note","default":""},"paid":{"type":"boolean","title":"Paid","default":true},"period":{"type":"string","title":"Period","default":""}},"type":"object","required":["category","usd"],"title":"ExpenseIn"},"ExperienceManifest":{"properties":{"schemaVersion":{"type":"integer","const":1,"title":"Schemaversion","default":1},"appId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$","title":"Appid"},"name":{"type":"string","maxLength":80,"minLength":1,"title":"Name"},"kioskUrl":{"type":"string","maxLength":2048,"title":"Kioskurl"},"controllerUrl":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Controllerurl"},"sessionSeconds":{"type":"integer","maximum":900.0,"minimum":30.0,"title":"Sessionseconds","default":180}},"additionalProperties":false,"type":"object","required":["appId","name","kioskUrl"],"title":"ExperienceManifest"},"ExperimentBody":{"properties":{"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"surface":{"type":"string","title":"Surface"},"variants":{"items":{"$ref":"#/components/schemas/ExperimentVariantBody"},"type":"array","maxItems":8,"minItems":2,"title":"Variants"},"status":{"type":"string","title":"Status","default":"active"},"kind":{"type":"string","title":"Kind","default":"look"},"confirm":{"type":"boolean","title":"Confirm","default":false},"operatorEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},"type":"object","required":["name","surface","variants"],"title":"ExperimentBody"},"ExperimentVariantBody":{"properties":{"key":{"type":"string","maxLength":64,"minLength":1,"title":"Key"},"weight":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Weight"},"presentation":{"additionalProperties":{"type":"string"},"type":"object","title":"Presentation"},"unitPriceUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unitpriceusd"}},"type":"object","required":["key","weight"],"title":"ExperimentVariantBody"},"FactorySignoffIn":{"properties":{"by":{"type":"string","title":"By"},"role":{"type":"string","title":"Role","default":""},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["by"],"title":"FactorySignoffIn"},"FeaturesBody":{"properties":{"remoteScreen":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Remotescreen"},"appAnalytics":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Appanalytics"},"autoRescue":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Autorescue"},"photobooth":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Photobooth"},"arcadePrintables":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Arcadeprintables"},"factoryMode":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Factorymode"},"deviceLogs":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Devicelogs"},"voiceShopper":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Voiceshopper"},"dropSound":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Dropsound"},"ambientAudio":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ambientaudio"},"cardTapStorefront":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cardtapstorefront"},"cardTapForceTile":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cardtapforcetile"},"htmlStorefront":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Htmlstorefront"},"testMode":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Testmode"},"merchOnDemand":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Merchondemand"},"figurines":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Figurines"},"walkupSensor":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Walkupsensor"},"walkupAlerts":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Walkupalerts"},"cameraLive":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cameralive"},"visionWatch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Visionwatch"}},"type":"object","title":"FeaturesBody"},"FirmwareIn":{"properties":{"vmcVersion":{"type":"string","title":"Vmcversion","default":""},"apkVersion":{"type":"string","title":"Apkversion","default":""}},"additionalProperties":false,"type":"object","title":"FirmwareIn"},"FlagBody":{"properties":{"titles":{"items":{"type":"string"},"type":"array","title":"Titles"},"featured":{"type":"string","title":"Featured"},"operatorEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},"type":"object","required":["titles","featured"],"title":"FlagBody"},"FleetMachineItem":{"properties":{"model":{"type":"string","title":"Model"},"qty":{"type":"integer","title":"Qty","default":1}},"type":"object","required":["model"],"title":"FleetMachineItem"},"FulfillRequest":{"properties":{"channel":{"type":"string","enum":["walkup","api_drop"],"title":"Channel","description":"walkup = on-machine sale only; api_drop = cloud remote dispense"},"machineNo":{"type":"string","maxLength":64,"minLength":3,"title":"Machineno"},"aisleNo":{"anyOf":[{"type":"integer","maximum":200.0,"minimum":1.0},{"type":"null"}],"title":"Aisleno"},"quantity":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Quantity","default":1},"reason":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Reason"},"externalRef":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Externalref"}},"type":"object","required":["channel","machineNo"],"title":"FulfillRequest"},"GameConfigBody":{"properties":{"gameEnabled":{"type":"boolean","title":"Gameenabled"}},"type":"object","required":["gameEnabled"],"title":"GameConfigBody"},"GeoTargetModel":{"properties":{"zips":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Zips","description":"5-digit US ZIP codes"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City","description":"City name (case-insensitive)"},"nationwide":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Nationwide","description":"Every machine in the network"}},"type":"object","title":"GeoTargetModel","description":"Geographic targeting: resolved to machines at flight time, so kiosks\nentering a targeted zip/city later are included automatically."},"GeocodeRetryRequest":{"properties":{"address":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Address","description":"Corrected address to try instead of the one already recorded"}},"type":"object","title":"GeocodeRetryRequest"},"Grant":{"properties":{"username":{"type":"string","maxLength":128,"minLength":1,"title":"Username"},"role":{"type":"string","title":"Role"},"operators":{"items":{"type":"string"},"type":"array","title":"Operators"},"zipCodes":{"items":{"type":"string"},"type":"array","title":"Zipcodes"},"states":{"items":{"type":"string"},"type":"array","title":"States"},"machineNos":{"items":{"type":"string"},"type":"array","title":"Machinenos"},"manufacturer":{"type":"string","maxLength":60,"title":"Manufacturer","default":""},"version":{"type":"integer","minimum":0.0,"title":"Version","default":0},"active":{"type":"boolean","title":"Active","default":true}},"type":"object","required":["username","role"],"title":"Grant"},"GroupCreate":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name"},"description":{"type":"string","maxLength":1000,"title":"Description","default":""}},"type":"object","required":["name"],"title":"GroupCreate"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HoursIn":{"properties":{"memberEmail":{"type":"string","title":"Memberemail"},"hours":{"type":"number","title":"Hours"},"workedOn":{"type":"string","title":"Workedon"},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["memberEmail","hours","workedOn"],"title":"HoursIn"},"IdeaIn":{"properties":{"title":{"type":"string","title":"Title"},"detail":{"type":"string","title":"Detail","default":""},"category":{"type":"string","title":"Category","default":"other"},"status":{"type":"string","title":"Status","default":"new"},"priority":{"type":"string","title":"Priority","default":"medium"},"expectedValueCents":{"type":"integer","title":"Expectedvaluecents","default":0},"votes":{"type":"integer","title":"Votes","default":0},"venueId":{"type":"string","title":"Venueid","default":""},"machineNo":{"type":"string","title":"Machineno","default":""}},"additionalProperties":false,"type":"object","required":["title"],"title":"IdeaIn"},"IdentityResetIn":{"properties":{"reason":{"type":"string","title":"Reason","description":"Why the identity is being cleared — which board was replaced, or which cabinet was mis-serialled"}},"type":"object","required":["reason"],"title":"IdentityResetIn"},"InboundRequest":{"properties":{"text":{"type":"string","maxLength":2000,"minLength":1,"title":"Text"},"channel":{"anyOf":[{"type":"string","pattern":"^(email|voice|chat|in_app)$"},{"type":"null"}],"title":"Channel","description":"Defaults to the thread's channel"}},"type":"object","required":["text"],"title":"InboundRequest"},"IngestItem":{"properties":{"url":{"type":"string","title":"Url"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"publishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publishedat"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"relevance":{"items":{"type":"object"},"type":"array","title":"Relevance"}},"type":"object","required":["url"],"title":"IngestItem"},"IngestRequest":{"properties":{"operatorEmail":{"type":"string","title":"Operatoremail"},"items":{"items":{"$ref":"#/components/schemas/IngestItem"},"type":"array","title":"Items"},"runId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Runid"}},"type":"object","required":["operatorEmail","items"],"title":"IngestRequest"},"InitiateTransferRequest":{"properties":{"recipientEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Recipientemail","description":"The receiving operator's account email (if you know it)"},"recipientId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Recipientid","description":"Stable account id from the recipient typeahead — lets you select a masked search result without knowing the full email"},"machineNos":{"items":{"type":"string"},"type":"array","maxItems":25,"minItems":1,"title":"Machinenos","description":"Machines to offer (one pending transfer each)"},"note":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Note"},"salePriceUsd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Salepriceusd","description":"Agreed sale price PER MACHINE. Recorded once and read by both operators' books: it is your disposal proceeds and the buyer's cost basis for the cabinet as a fixed asset. Leave it out for a hand-over with no consideration — you then write off the remaining book value and the machine arrives unpriced on their sheet."}},"additionalProperties":false,"type":"object","required":["machineNos"],"title":"InitiateTransferRequest"},"InputBody":{"properties":{"type":{"type":"string","pattern":"^(tap|swipe|back|home|text)$","title":"Type"},"coordinateSpace":{"anyOf":[{"type":"string","enum":["normalized","pixels"]},{"type":"null"}],"title":"Coordinatespace"},"x":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"X"},"y":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Y"},"x2":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"X2"},"y2":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Y2"},"text":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Text"},"durationMs":{"type":"integer","maximum":2000.0,"minimum":20.0,"title":"Durationms","default":120}},"type":"object","required":["type"],"title":"InputBody","description":"Raw device pixels by default; new agents also accept normalized 0..1."},"InstallOrderUpdate":{"properties":{"status":{"type":"string","title":"Status"},"assignee":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assignee"},"schedule":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schedule"}},"type":"object","required":["status"],"title":"InstallOrderUpdate"},"InstallStartRequest":{"properties":{"hardwareVariant":{"type":"string","title":"Hardwarevariant"}},"type":"object","required":["hardwareVariant"],"title":"InstallStartRequest"},"InstallationRequest":{"properties":{"expectedFingerprint":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Expectedfingerprint"},"confirmed":{"type":"boolean","title":"Confirmed"},"machineReference":{"type":"string","maxLength":128,"minLength":1,"title":"Machinereference"},"placementNote":{"type":"string","maxLength":500,"minLength":1,"title":"Placementnote"}},"additionalProperties":false,"type":"object","required":["expectedFingerprint","confirmed","machineReference","placementNote"],"title":"InstallationRequest"},"JobCreateRequest":{"properties":{"machineNo":{"type":"string","maxLength":32,"minLength":8,"title":"Machineno"},"kind":{"type":"string","pattern":"^(refill|sku_order)$","title":"Kind","default":"refill"},"payoutUsd":{"type":"number","maximum":500.0,"minimum":1.0,"title":"Payoutusd"},"marketplace":{"type":"boolean","title":"Marketplace","description":"Publish to the broker marketplace","default":true},"notes":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Notes"}},"type":"object","required":["machineNo","payoutUsd"],"title":"JobCreateRequest"},"JourneyRequest":{"properties":{"stage":{"type":"string","title":"Stage","description":"One of: solo, field, fleet, growth, enterprise"},"active":{"type":"boolean","title":"Active","description":"Activate (true) or deactivate the stage","default":true}},"type":"object","required":["stage"],"title":"JourneyRequest"},"LaunchFleetRequest":{"properties":{"machines":{"anyOf":[{"items":{"$ref":"#/components/schemas/FleetMachineItem"},"type":"array"},{"type":"null"}],"title":"Machines"},"areas":{"items":{"type":"string"},"type":"array","title":"Areas","default":[]},"verticals":{"items":{"type":"string"},"type":"array","title":"Verticals","default":[]},"mode":{"type":"string","title":"Mode","default":"checkpoint"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"investUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Investusd"},"investModel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Investmodel"},"confirm":{"type":"boolean","title":"Confirm","default":false}},"additionalProperties":false,"type":"object","title":"LaunchFleetRequest"},"LeadIn":{"properties":{"displayName":{"type":"string","title":"Displayname","default":""},"email":{"type":"string","title":"Email","default":""},"phone":{"type":"string","title":"Phone","default":""},"companyName":{"type":"string","title":"Companyname","default":""},"stage":{"type":"string","title":"Stage","default":"new"},"source":{"type":"string","title":"Source","default":"other"},"venueId":{"type":"string","title":"Venueid","default":""},"dfyDealId":{"type":"string","title":"Dfydealid","default":""},"kioskMachineNo":{"type":"string","title":"Kioskmachineno","default":""},"unclaimed":{"type":"boolean","title":"Unclaimed","default":false},"operatorEmail":{"type":"string","title":"Operatoremail","default":""}},"type":"object","title":"LeadIn"},"LeaseChatRequest":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"LeaseChatRequest"},"LinkMachineRequest":{"properties":{"machineNo":{"type":"string","title":"Machineno"}},"type":"object","required":["machineNo"],"title":"LinkMachineRequest"},"LiveBody":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"seconds":{"type":"integer","maximum":300.0,"minimum":5.0,"title":"Seconds","default":60},"interval":{"type":"integer","maximum":30.0,"minimum":1.0,"title":"Interval","default":3}},"type":"object","title":"LiveBody"},"LoginRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"LoginRequest"},"LotIn":{"properties":{"sku":{"type":"string","title":"Sku"},"qty":{"type":"number","title":"Qty"},"unitCostUsd":{"type":"number","title":"Unitcostusd"},"poRef":{"type":"string","title":"Poref","default":""},"receivedOn":{"type":"string","title":"Receivedon","default":""}},"type":"object","required":["sku","qty","unitCostUsd"],"title":"LotIn"},"MachineRegisterRequest":{"properties":{"machineNo":{"type":"string","maxLength":32,"minLength":8,"pattern":"^[0-9A-Za-z-]+$","title":"Machineno"},"name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Name"},"location":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Location"},"lat":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lat"},"lng":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lng"},"operatorEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail","description":"Admin only: register the machine into this operator's fleet"}},"type":"object","required":["machineNo"],"title":"MachineRegisterRequest"},"MachineUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Name"},"notes":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Notes"},"location":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Location"},"lat":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lat"},"lng":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lng"},"address":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Address","description":"Street address to geocode server-side into lat/lng (+placeId)"},"placeId":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Placeid"},"timeZone":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Timezone","description":"IANA zone of the VENUE (e.g. Pacific/Auckland) for the cabinet's on-screen clock; \"\" clears it and returns to the zone derived from the placement"},"salesTaxRate":{"anyOf":[{"type":"number","maximum":0.3,"minimum":0.0},{"type":"null"}],"title":"Salestaxrate","description":"Jurisdiction sales-tax rate of this cabinet's location (e.g. 0.08875 for NYC), overriding the operator's tax schedule for its sales. Applied to the nearest basis point; prices stay tax-inclusive."},"ageVerification":{"anyOf":[{"$ref":"#/components/schemas/AgeVerificationPolicy"},{"type":"null"}]},"venueId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Venueid","description":"Place this machine at an existing CRM venue, so its host starts earning commission. Accrual opens now — sales already taken are reported, never back-dated."},"hostArrangement":{"anyOf":[{"type":"string","pattern":"^(none|host)$"},{"type":"null"}],"title":"Hostarrangement","description":"\"none\" records that this machine genuinely has no host (your own retail space, a warehouse unit) so it stops appearing as an unhosted-sales exception; \"host\" withdraws that and expects a venue link again."},"hostArrangementReason":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Hostarrangementreason","description":"Why this machine has no host, kept with the declaration"}},"additionalProperties":true,"type":"object","title":"MachineUpdateRequest"},"MarkReadRequest":{"properties":{"notifIds":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Notifids"}},"type":"object","title":"MarkReadRequest"},"MechanicFlags":{"properties":{"spin":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Spin"},"scratch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Scratch"},"draws":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Draws"}},"type":"object","title":"MechanicFlags"},"MemberHoursIn":{"properties":{"hours":{"type":"number","title":"Hours"},"workedOn":{"type":"string","title":"Workedon"},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["hours","workedOn"],"title":"MemberHoursIn"},"MemberIn":{"properties":{"name":{"type":"string","title":"Name"},"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role","default":""},"phone":{"type":"string","title":"Phone","default":""},"routeName":{"type":"string","title":"Routename","default":""},"machineNos":{"items":{"type":"string"},"type":"array","title":"Machinenos"},"active":{"type":"boolean","title":"Active","default":true},"startedOn":{"type":"string","title":"Startedon","default":""},"usdPerHour":{"type":"number","title":"Usdperhour","default":0.0}},"additionalProperties":true,"type":"object","required":["name","email"],"title":"MemberIn"},"ModePatch":{"properties":{"preset":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preset"},"toggles":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"type":"object"},{"type":"null"}],"title":"Toggles"}},"type":"object","title":"ModePatch"},"NayaxBindRequest":{"properties":{"terminalId":{"type":"string","maxLength":32,"minLength":6,"pattern":"^[0-9A-Za-z_-]{6,32}$","title":"Terminalid","description":"The reader's real Nayax Device Number (terminal ID)"},"deviceSerial":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Deviceserial"},"model":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Model"},"merchantAccountId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Merchantaccountid","description":"Override the settlement account (defaults to the operator's Nayax merchant account)"},"merchantAccountName":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Merchantaccountname"},"coreActorName":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Coreactorname","description":"The actor that owns this Device Number in Nayax Core, if it is not this operator (e.g. a second-hand cabinet whose reader was never moved between actors)"},"settlesToOperator":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Settlestooperator","description":"False when card takings settle to coreActorName instead of this operator. Kiosk-X cannot read Core, so this is asserted by whoever onboards the reader — and it stops the money views crediting this operator for captures it never receives."},"nayaxWebhookExpected":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Nayaxwebhookexpected","description":"Whether this reader's Core actor sends settlement notifications to Kiosk-X. False for a foreign actor that keeps its own notifications: a shipped order then legitimately has no transactionId, and must not be read as a ghost sale."},"cardMode":{"anyOf":[{"type":"string","pattern":"^(mdb|spark)$"},{"type":"null"}],"title":"Cardmode","description":"How a tap is obtained. 'mdb' (default) is the reader as a cashless peripheral on the controller's bus. 'spark' drives it from our cloud via Nayax's remote-start API — for a reader commissioned for an MDB dialect this controller does not speak."}},"type":"object","required":["terminalId"],"title":"NayaxBindRequest"},"NegotiationStartRequest":{"properties":{"channel":{"type":"string","title":"Channel","default":"voice"},"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","title":"NegotiationStartRequest"},"NotifAck":{"properties":{"tzOffsetMinutes":{"type":"integer","maximum":840.0,"minimum":-840.0,"title":"Tzoffsetminutes","default":0}},"type":"object","title":"NotifAck"},"NudgeActionRequest":{"properties":{"action":{"type":"string","title":"Action"}},"type":"object","required":["action"],"title":"NudgeActionRequest"},"OfferAcceptRequest":{"properties":{"esignConsent":{"type":"boolean","title":"Esignconsent","default":false},"signerName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signername"},"signerTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signertitle"},"createBasePlan":{"type":"boolean","title":"Createbaseplan","description":"Start the machine's base plan when none exists","default":false}},"type":"object","title":"OfferAcceptRequest","description":"Acknowledge → approve → e-sign, consent-gated exactly like the rider\nendpoint: no ESIGN/UETA consent, no signing link (428)."},"OfferDeclineRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Reason"}},"type":"object","title":"OfferDeclineRequest"},"OnboardingCompleteRequest":{"properties":{"force":{"type":"boolean","title":"Force","description":"Complete despite failing checks (non-production full-admin sandbox only)","default":false}},"type":"object","title":"OnboardingCompleteRequest"},"OperatorTurnRequest":{"properties":{"message":{"type":"string","title":"Message"},"terms":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Terms"}},"type":"object","required":["message"],"title":"OperatorTurnRequest"},"OrderRequest":{"properties":{"model":{"type":"string","title":"Model"},"preOrder":{"type":"boolean","title":"Preorder","default":false},"successUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Successurl"},"cancelUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancelurl"},"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","required":["model"],"title":"OrderRequest"},"OrderStatusRequest":{"properties":{"status":{"type":"string","title":"Status"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"},"tracking":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking"}},"type":"object","required":["status"],"title":"OrderStatusRequest"},"OriginBody":{"properties":{"lat":{"type":"number","maximum":90.0,"minimum":-90.0,"title":"Lat"},"lng":{"type":"number","maximum":180.0,"minimum":-180.0,"title":"Lng"}},"type":"object","required":["lat","lng"],"title":"OriginBody"},"OutcomeRequest":{"properties":{"outcome":{"type":"string","title":"Outcome"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["outcome"],"title":"OutcomeRequest"},"OutreachDraftRequest":{"properties":{"candidateId":{"type":"string","title":"Candidateid"}},"type":"object","required":["candidateId"],"title":"OutreachDraftRequest"},"OutreachStartRequest":{"properties":{"candidateIds":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Candidateids"},"confirm":{"type":"boolean","title":"Confirm","default":false},"channelOrder":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Channelorder"}},"type":"object","title":"OutreachStartRequest"},"PayIn":{"properties":{"memberEmail":{"type":"string","title":"Memberemail"},"usd":{"type":"number","title":"Usd"},"period":{"type":"string","title":"Period"},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["memberEmail","usd","period"],"title":"PayIn"},"PayoutIn":{"properties":{"venueId":{"type":"string","title":"Venueid"},"usd":{"type":"number","title":"Usd"},"period":{"type":"string","title":"Period"},"achLast4":{"type":"string","title":"Achlast4","default":""}},"type":"object","required":["venueId","usd","period"],"title":"PayoutIn"},"PhaseIn":{"properties":{"reason":{"type":"string","title":"Reason","description":"Why the rollout was held or resumed","default":""}},"type":"object","title":"PhaseIn"},"PinIn":{"properties":{"version":{"type":"string","title":"Version","description":"The published version to hold this cabinet at"},"reason":{"type":"string","title":"Reason","description":"Why this cabinet is exempt from the rollout"}},"type":"object","required":["version","reason"],"title":"PinIn"},"PlaceOrderRequest":{"properties":{"manufacturer":{"type":"string","title":"Manufacturer","default":"hotbox"},"fulfillment":{"type":"string","title":"Fulfillment","default":"in_stock"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"}},"type":"object","title":"PlaceOrderRequest"},"PlacementIn":{"properties":{"machineNo":{"type":"string","title":"Machineno"},"move":{"type":"boolean","title":"Move","default":true},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["machineNo"],"title":"PlacementIn"},"PrefsPatch":{"properties":{"notifications":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Notifications"},"pinnedMachines":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Pinnedmachines"},"savedViews":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Savedviews"},"briefingOrder":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Briefingorder"},"leaderboard":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Leaderboard"},"assistantContext":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Assistantcontext"}},"type":"object","title":"PrefsPatch"},"PreorderRequest":{"properties":{"model":{"type":"string","title":"Model"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"successUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Successurl"},"cancelUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancelurl"},"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","required":["model"],"title":"PreorderRequest"},"PricingModel":{"properties":{"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"flat-monthly | cpm"},"monthlyRatePerMachine":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Monthlyratepermachine"},"cpmRate":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Cpmrate"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","default":"USD"}},"type":"object","title":"PricingModel"},"ProfileUpdate":{"properties":{"handle":{"anyOf":[{"type":"string","maxLength":24,"minLength":3},{"type":"null"}],"title":"Handle"},"displayName":{"anyOf":[{"type":"string","maxLength":40,"minLength":1},{"type":"null"}],"title":"Displayname"},"avatarEmoji":{"anyOf":[{"type":"string","maxLength":8,"minLength":1},{"type":"null"}],"title":"Avataremoji"},"region":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Region","description":"Coarse region only (city/state) — never an address"},"shareRegion":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Shareregion"},"discoverable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Discoverable"},"nakamaUserId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Nakamauserid"},"nakamaUsername":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Nakamausername"}},"type":"object","title":"ProfileUpdate"},"ProgramUpdate":{"properties":{"mechanics":{"anyOf":[{"$ref":"#/components/schemas/MechanicFlags"},{"type":"null"}]},"monthlyCapCents":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":0.0},{"type":"null"}],"title":"Monthlycapcents"},"grandPrizeRetail":{"anyOf":[{"type":"number","maximum":100.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Grandprizeretail"},"smallPrizeRetail":{"anyOf":[{"type":"number","maximum":100.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Smallprizeretail"},"drawPrizeRetail":{"anyOf":[{"type":"number","maximum":1000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Drawprizeretail"}},"type":"object","title":"ProgramUpdate"},"ProgramUpdateRequest":{"properties":{"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"maxPrice":{"anyOf":[{"type":"number","maximum":1000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Maxprice"},"fundingSourceId":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Fundingsourceid"},"campaignId":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Campaignid"}},"type":"object","title":"ProgramUpdateRequest"},"PromoteBody":{"properties":{"variant":{"type":"string","maxLength":64,"minLength":1,"title":"Variant"},"operatorEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail"}},"type":"object","required":["variant"],"title":"PromoteBody"},"PromoteIn":{"properties":{"dueOn":{"type":"string","title":"Dueon","default":""},"notes":{"type":"string","title":"Notes","default":""}},"type":"object","title":"PromoteIn"},"ProtectionPlanRequest":{"properties":{"esignConsent":{"type":"boolean","title":"Esignconsent","default":false},"signerName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signername"},"signerTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signertitle"}},"type":"object","title":"ProtectionPlanRequest","description":"ESIGN/UETA consent gate — no consent, no signing link.\n\nThe UI must show the electronic-records disclosure\n(GET /api/v1/legal/esign-disclosure) and an unchecked consent box; the\noperator's affirmative act arrives here as ``esignConsent: true`` with\nthe signer's name/title for attribution."},"ProvenanceBody":{"properties":{"manufacturer":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Manufacturer"},"shipDate":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Shipdate","description":"ISO date the unit left the factory"}},"type":"object","title":"ProvenanceBody"},"PublicationRequest":{"properties":{"expectedRevision":{"type":"integer","minimum":0.0,"title":"Expectedrevision"},"enabled":{"type":"boolean","title":"Enabled"},"manifest":{"anyOf":[{"$ref":"#/components/schemas/ExperienceManifest"},{"type":"null"}]}},"additionalProperties":false,"type":"object","required":["expectedRevision","enabled"],"title":"PublicationRequest"},"PurchaseIn":{"properties":{"lines":{"items":{"$ref":"#/components/schemas/PurchaseLine"},"type":"array","title":"Lines"},"poRef":{"type":"string","title":"Poref","default":""},"vendor":{"type":"string","title":"Vendor","default":""},"orderedOn":{"type":"string","title":"Orderedon","default":""},"paidUsd":{"type":"number","title":"Paidusd","default":0.0},"note":{"type":"string","title":"Note","default":""}},"additionalProperties":true,"type":"object","title":"PurchaseIn"},"PurchaseLine":{"properties":{"sku":{"type":"string","title":"Sku"},"qty":{"type":"number","title":"Qty"},"unitCostUsd":{"type":"number","title":"Unitcostusd"}},"additionalProperties":true,"type":"object","required":["sku","qty","unitCostUsd"],"title":"PurchaseLine"},"PurchasePayIn":{"properties":{"usd":{"type":"number","title":"Usd"}},"type":"object","required":["usd"],"title":"PurchasePayIn"},"QaSessionBody":{"properties":{"machineNo":{"type":"string","maxLength":128,"minLength":1,"title":"Machineno"}},"type":"object","required":["machineNo"],"title":"QaSessionBody"},"RateIn":{"properties":{"memberEmail":{"type":"string","title":"Memberemail"},"usdPerHour":{"type":"number","title":"Usdperhour"}},"type":"object","required":["memberEmail","usdPerHour"],"title":"RateIn"},"ReceiveOrderRequest":{"properties":{"actualCostUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Actualcostusd"}},"additionalProperties":false,"type":"object","title":"ReceiveOrderRequest"},"ReconcileStrandedRequest":{"properties":{"olderThanSeconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Olderthanseconds"}},"type":"object","title":"ReconcileStrandedRequest"},"RecoveryBody":{"properties":{"mfaTicket":{"type":"string","minLength":8,"title":"Mfaticket"},"recoveryCode":{"type":"string","maxLength":64,"minLength":4,"title":"Recoverycode"}},"type":"object","required":["mfaTicket","recoveryCode"],"title":"RecoveryBody"},"ReferralPayoutIn":{"properties":{"referrerEmail":{"type":"string","title":"Referreremail"},"usd":{"type":"number","title":"Usd"},"period":{"type":"string","title":"Period","default":""},"venueId":{"type":"string","title":"Venueid","default":""},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["referrerEmail","usd"],"title":"ReferralPayoutIn"},"Referrer":{"properties":{"email":{"type":"string","title":"Email"},"bps":{"type":"integer","title":"Bps","default":0}},"type":"object","required":["email"],"title":"Referrer"},"RefundFailureRequest":{"properties":{"error":{"type":"string","title":"Error"},"permanent":{"type":"boolean","title":"Permanent","default":false}},"type":"object","required":["error"],"title":"RefundFailureRequest"},"RejectRequest":{"properties":{"reason":{"type":"string","minLength":3,"title":"Reason","examples":["Creative conflicts with an exclusive sponsorship"]}},"type":"object","required":["reason"],"title":"RejectRequest"},"RelocateRequest":{"properties":{"toAddress":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Toaddress"},"toLat":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tolat"},"toLng":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tolng"},"reason":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Reason","description":"e.g. the Yield Scout suggestion"}},"type":"object","title":"RelocateRequest"},"ResolveExceptionRequest":{"properties":{"status":{"type":"string","title":"Status"},"resolution":{"type":"string","title":"Resolution"}},"type":"object","required":["status","resolution"],"title":"ResolveExceptionRequest"},"RestockIn":{"properties":{"machineNo":{"type":"string","title":"Machineno"},"lines":{"items":{"$ref":"#/components/schemas/RestockLine"},"type":"array","title":"Lines"},"byEmail":{"type":"string","title":"Byemail","default":""},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["machineNo"],"title":"RestockIn"},"RestockLine":{"properties":{"aisleNo":{"type":"integer","minimum":1.0,"title":"Aisleno"},"qty":{"type":"number","multipleOf":1.0,"exclusiveMinimum":0.0,"title":"Qty"}},"type":"object","required":["aisleNo","qty"],"title":"RestockLine"},"RestockRequest":{"properties":{"aisles":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Aisles"},"note":{"anyOf":[{"type":"string","maxLength":280},{"type":"null"}],"title":"Note"}},"additionalProperties":false,"type":"object","title":"RestockRequest"},"RestockRunCreate":{"properties":{"machine_no":{"type":"string","title":"Machine No"},"assigned_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assigned To"}},"type":"object","required":["machine_no"],"title":"RestockRunCreate"},"RestockRunUpdate":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"assigned_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assigned To"}},"type":"object","title":"RestockRunUpdate"},"RetireRequest":{"properties":{"mode":{"type":"string","enum":["retired","resold","returned"],"title":"Mode","description":"retired = end of life; resold = sold/transferred (next owner claims the serial); returned = returned/refunded","default":"retired"},"reason":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Reason"},"proceedsUsd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Proceedsusd","description":"What you actually received for the cabinet, if anything: scrap value, an off-platform sale, a refund. Recorded as the proceeds on the fixed-asset disposal, so the gain or loss on your balance sheet is proceeds less net book value. Leave it out for a write-off — nothing is assumed, because inventing proceeds would overstate your profit. For a sale to another operator ON the platform use the transfer flow instead (POST /api/v1/transfers): the price is recorded once there and read by both sets of books."}},"type":"object","title":"RetireRequest"},"Review":{"properties":{"lanes":{"items":{"$ref":"#/components/schemas/ReviewLane"},"type":"array","maxItems":891,"minItems":1,"title":"Lanes"}},"additionalProperties":false,"type":"object","required":["lanes"],"title":"Review"},"ReviewLane":{"properties":{"aisleNo":{"type":"integer","title":"Aisleno"},"result":{"type":"string","enum":["matches","mismatch","uncertain"],"title":"Result"}},"additionalProperties":false,"type":"object","required":["aisleNo","result"],"title":"ReviewLane"},"ReviewRequest":{"properties":{"action":{"type":"string","title":"Action"}},"type":"object","required":["action"],"title":"ReviewRequest"},"RevokeBody":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"allowReenrolment":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Allowreenrolment"}},"type":"object","title":"RevokeBody"},"RevokeIn":{"properties":{"venueId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Venueid"},"token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token"}},"type":"object","title":"RevokeIn"},"RolesRequest":{"properties":{"roles":{"items":{"type":"string"},"type":"array","title":"Roles","description":"Self-declared segments: field_tech, fleet_owner, investor, venue, franchise, distributor, enterprise, refiller"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Crew or operator email to attach the roles to"}},"type":"object","required":["roles"],"title":"RolesRequest"},"RolloutCreateRequest":{"properties":{"version":{"type":"string","title":"Version","description":"Target APK version (semver-ish)","examples":["1.0.43"]},"apkUrl":{"type":"string","title":"Apkurl","description":"Signed APK artifact URL (HTTPS S3/CDN)","default":"https://media.intelli-verse-x.ai/downloads/reyeah-vending-kioskx-1.2.8-a428bd2a020f.apk"},"apkSha256":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Apksha256","description":"Hex sha256 of the APK; returned in the update offer so the device can verify the artifact before installing."},"fileName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename","description":"Defaults to the URL's basename"},"notes":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Notes"},"strategy":{"anyOf":[{"$ref":"#/components/schemas/RolloutStrategy"},{"type":"null"}],"description":"Default: 100% of your fleet"},"appId":{"type":"string","title":"Appid","description":"Client package this build targets: com.ruiye.jd (Reyeah vending APK, default) or ai.intelliverse.zhzn.kioskx (ZHZN agent). Devices are only ever offered builds for their own package.","default":"com.ruiye.jd"},"versionCode":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Versioncode","description":"Android versionCode (required for ZHZN agent builds — the on-device OTA gate compares integer versionCodes)."},"nudge":{"type":"boolean","title":"Nudge","description":"Ask the leading edge of the wave to check for the update immediately instead of waiting out their next OTA check. Bounded — at most 25 machines per call, so publishing a fleet-wide rollout cannot stampede S3 or the machines' uplinks.","default":true}},"type":"object","required":["version"],"title":"RolloutCreateRequest"},"RolloutIn":{"properties":{"targetVersion":{"type":"string","title":"Targetversion","description":"The published version the fleet is aimed at"},"phase":{"type":"string","title":"Phase","description":"held | rolling | complete","default":"rolling"},"canary":{"items":{"type":"string"},"type":"array","title":"Canary","description":"Machine codes that get it regardless of percent"},"percent":{"type":"integer","title":"Percent","description":"Share of the remaining fleet, 0-100","default":0},"allowDowngrade":{"type":"boolean","title":"Allowdowngrade","description":"Permit cabinets above the target to move back down to it","default":false},"note":{"type":"string","title":"Note","description":"Why this rollout exists — shown in the coverage view","default":""}},"type":"object","required":["targetVersion"],"title":"RolloutIn"},"RolloutStrategy":{"properties":{"machines":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Machines","description":"Explicit machine list (canary rollout)"},"percentage":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":1.0},{"type":"null"}],"title":"Percentage","description":"Deterministic fleet percentage (staged rollout)"}},"type":"object","title":"RolloutStrategy"},"ScoutOutreachBody":{"properties":{"rank":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Rank","description":"Which scouted result to hand off (result.rank)"},"dealId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dealid","description":"Attach to an existing DFY deal (must be yours and not past outreach); omit to open a new deal"},"title":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Title"},"autoOutreach":{"type":"boolean","title":"Autooutreach","default":true},"confirm":{"type":"boolean","title":"Confirm","description":"Explicit operator confirmation — this arms REAL calls/emails to the venue (the one-tap gate)","default":false}},"type":"object","required":["rank"],"title":"ScoutOutreachBody"},"ScoutRequestBody":{"properties":{"query":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}],"title":"Query","description":"Free-text ask, e.g. '3 schools in a 3 mile radius, zip code 75001' — parsed into structured constraints"},"origin":{"anyOf":[{"$ref":"#/components/schemas/OriginBody"},{"type":"null"}]},"address":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Address","description":"Anchor address/ZIP/place name"},"desiredAreas":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":5},{"type":"null"}],"title":"Desiredareas","description":"Up to 5 areas to scout (addresses/ZIPs)"},"radiusKm":{"anyOf":[{"type":"number","maximum":60.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Radiuskm"},"keywords":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":6},{"type":"null"}],"title":"Keywords","description":"Verticals from GET /keywords"},"venueRequirements":{"anyOf":[{"items":{"$ref":"#/components/schemas/VenueRequirementBody"},"type":"array"},{"type":"null"}],"title":"Venuerequirements"}},"type":"object","title":"ScoutRequestBody"},"SelectRequest":{"properties":{"candidateId":{"type":"string","title":"Candidateid"}},"type":"object","required":["candidateId"],"title":"SelectRequest"},"SendLeaseRequest":{"properties":{"recipientName":{"type":"string","title":"Recipientname"},"recipientEmail":{"type":"string","title":"Recipientemail"},"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","required":["recipientName","recipientEmail"],"title":"SendLeaseRequest"},"SensitiveIn":{"properties":{"label":{"type":"string","title":"Label"},"value":{"type":"string","title":"Value"},"kind":{"type":"string","title":"Kind","default":"other"},"venueId":{"type":"string","title":"Venueid","default":""},"machineNo":{"type":"string","title":"Machineno","default":""},"notes":{"type":"string","title":"Notes","default":""}},"type":"object","required":["label","value"],"title":"SensitiveIn"},"SessionCheck":{"properties":{"nonce":{"type":"string","maxLength":200,"minLength":20,"title":"Nonce"},"mfaProof":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mfaproof"}},"type":"object","required":["nonce"],"title":"SessionCheck"},"SessionRequest":{"properties":{"password":{"type":"string","title":"Password"},"totpCode":{"type":"string","title":"Totpcode"}},"type":"object","required":["password","totpCode"],"title":"SessionRequest"},"SettingsPatch":{"properties":{"autopilot":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Autopilot"},"autoApproveScore":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Autoapprovescore"},"maxAutoApprove":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Maxautoapprove"},"scoutAutoHandoffMax":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Scoutautohandoffmax"},"installMode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Installmode"},"autoInventory":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Autoinventory"},"inventoryMonthlyCapUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inventorymonthlycapusd"},"moneyThresholdUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Moneythresholdusd"},"capabilities":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"type":"object"},{"type":"null"}],"title":"Capabilities"},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Displayname"},"channelOrder":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Channelorder"}},"additionalProperties":false,"type":"object","title":"SettingsPatch"},"ShareIn":{"properties":{"venueId":{"type":"string","title":"Venueid"},"period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period"}},"type":"object","required":["venueId"],"title":"ShareIn"},"ShipRequest":{"properties":{"trackingRef":{"type":"string","title":"Trackingref"}},"type":"object","required":["trackingRef"],"title":"ShipRequest"},"ShippingIn":{"properties":{"carrier":{"type":"string","title":"Carrier","default":""},"trackingNumber":{"type":"string","title":"Trackingnumber","default":""},"consignmentRef":{"type":"string","title":"Consignmentref","default":""},"shipToName":{"type":"string","title":"Shiptoname","default":""},"shipToAddress":{"type":"string","title":"Shiptoaddress","default":""},"shipToCity":{"type":"string","title":"Shiptocity","default":""},"shipToRegion":{"type":"string","title":"Shiptoregion","default":""},"shipToPostal":{"type":"string","title":"Shiptopostal","default":""},"shipToCountry":{"type":"string","title":"Shiptocountry","default":""},"notes":{"type":"string","title":"Notes","default":""}},"additionalProperties":false,"type":"object","title":"ShippingIn","description":"The crate's paperwork, keyed to the serial.\n\nDistinct from the deal-level tracking string on a manufacturing order:\nthat answers \"where is my order?\"; this answers \"where is THIS cabinet\ngoing, and on which waybill?\". Written by the factory (or a full admin)\nthrough the same PUT as the rest of the build record, which is the\nmanufacturer.kiosk-x.ai contract."},"ShortlistRequest":{"properties":{"area":{"type":"string","title":"Area"},"vertical":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"},"keywords":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Keywords"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["area"],"title":"ShortlistRequest"},"SkuDropRequest":{"properties":{"product":{"type":"string","maxLength":120,"minLength":2,"title":"Product"}},"type":"object","required":["product"],"title":"SkuDropRequest"},"SocialLoginRequest":{"properties":{"provider":{"type":"string","title":"Provider"},"idToken":{"type":"string","title":"Idtoken"}},"type":"object","required":["provider","idToken"],"title":"SocialLoginRequest"},"SopIn":{"properties":{"title":{"type":"string","title":"Title"},"category":{"type":"string","title":"Category","default":"other"},"summary":{"type":"string","title":"Summary","default":""},"steps":{"items":{"type":"string"},"type":"array","title":"Steps"},"reviewOn":{"type":"string","title":"Reviewon","default":""}},"type":"object","required":["title"],"title":"SopIn"},"StreakTouchRequest":{"properties":{"source":{"type":"string","title":"Source","description":"briefing | plan_step"},"tzOffsetMinutes":{"type":"integer","maximum":840.0,"minimum":-840.0,"title":"Tzoffsetminutes","default":0},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone","description":"IANA zone; preferred over the offset"}},"type":"object","required":["source"],"title":"StreakTouchRequest"},"StructuredAddress":{"properties":{"houseNumber":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Housenumber"},"street":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}],"title":"Street"},"unit":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Unit"},"locality":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Locality"},"region":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Region"},"postalCode":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Postalcode"},"country":{"anyOf":[{"type":"string","maxLength":2},{"type":"null"}],"title":"Country"}},"additionalProperties":false,"type":"object","title":"StructuredAddress"},"SubscribeBody":{"properties":{"source":{"type":"string","maxLength":40,"title":"Source","default":"operator-x-app"},"revenueCatRef":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Revenuecatref","description":"Store transaction reference when activated through in-app purchase (RevenueCat)"}},"type":"object","title":"SubscribeBody"},"TaskIn":{"properties":{"title":{"type":"string","title":"Title"},"status":{"type":"string","title":"Status","default":"open"},"venueId":{"type":"string","title":"Venueid","default":""},"machineNo":{"type":"string","title":"Machineno","default":""},"notes":{"type":"string","title":"Notes","default":""},"dueOn":{"type":"string","title":"Dueon","default":""}},"additionalProperties":true,"type":"object","required":["title"],"title":"TaskIn"},"TaxIn":{"properties":{"bps":{"type":"integer","title":"Bps"},"effectiveAt":{"type":"string","title":"Effectiveat"}},"type":"object","required":["bps","effectiveAt"],"title":"TaxIn"},"TestIn":{"properties":{"code":{"type":"string","title":"Code"},"result":{"type":"string","title":"Result"},"detail":{"type":"string","title":"Detail","default":""},"testedAt":{"type":"string","title":"Testedat","default":""},"testedBy":{"type":"string","title":"Testedby","default":""},"suite":{"type":"string","title":"Suite","default":""}},"type":"object","required":["code","result"],"title":"TestIn"},"TestsIn":{"properties":{"results":{"items":{"$ref":"#/components/schemas/TestIn"},"type":"array","title":"Results"},"suite":{"type":"string","title":"Suite","default":""}},"type":"object","title":"TestsIn"},"TicketBody":{"properties":{"mfaTicket":{"type":"string","minLength":8,"title":"Mfaticket"}},"type":"object","required":["mfaTicket"],"title":"TicketBody"},"TicketCreate":{"properties":{"subject":{"type":"string","title":"Subject"},"message":{"type":"string","title":"Message"}},"type":"object","required":["subject","message"],"title":"TicketCreate"},"TicketReply":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"TicketReply"},"TransitionRequest":{"properties":{"toStage":{"type":"string","title":"Tostage","description":"Target canonical stage"},"detail":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Detail"},"force":{"type":"boolean","title":"Force","description":"Admin only: audited override of the legal-transition check","default":false}},"type":"object","required":["toStage"],"title":"TransitionRequest"},"UnlockIn":{"properties":{"password":{"type":"string","title":"Password"}},"type":"object","required":["password"],"title":"UnlockIn"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VenueIn":{"properties":{"name":{"type":"string","title":"Name"},"kioskMachineNo":{"type":"string","title":"Kioskmachineno","default":""},"machineNos":{"items":{"type":"string"},"type":"array","title":"Machinenos"},"status":{"type":"string","title":"Status","default":""},"businessHours":{"type":"string","title":"Businesshours","default":""},"businessType":{"type":"string","title":"Businesstype","default":""},"deploymentDate":{"type":"string","title":"Deploymentdate","default":""},"leaseRenewalOn":{"type":"string","title":"Leaserenewalon","default":""},"leaseEndsOn":{"type":"string","title":"Leaseendson","default":""},"commissionBasis":{"type":"string","title":"Commissionbasis","default":"net_revenue"},"revShareBps":{"type":"integer","title":"Revsharebps","default":0},"minGuaranteeCents":{"type":"integer","title":"Minguaranteecents","default":0},"flatRentCents":{"type":"integer","title":"Flatrentcents","default":0},"perVendCents":{"type":"integer","title":"Pervendcents","default":0},"referrers":{"items":{"$ref":"#/components/schemas/Referrer"},"type":"array","title":"Referrers"},"contactName":{"type":"string","title":"Contactname","default":""},"contactEmail":{"type":"string","title":"Contactemail","default":""},"contactPhone":{"type":"string","title":"Contactphone","default":""},"achLast4":{"type":"string","title":"Achlast4","default":""},"achAccount":{"type":"string","title":"Achaccount","default":""},"routingNumber":{"type":"string","title":"Routingnumber","default":""},"address":{"type":"string","title":"Address","default":""},"notes":{"type":"string","title":"Notes","default":""}},"additionalProperties":true,"type":"object","required":["name"],"title":"VenueIn"},"VenueRequirementBody":{"properties":{"venueType":{"type":"string","maxLength":40,"title":"Venuetype"},"minCount":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Mincount","default":1}},"type":"object","required":["venueType"],"title":"VenueRequirementBody"},"VisionBody":{"properties":{"watch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Watch"},"everySeconds":{"anyOf":[{"type":"integer","maximum":3600.0,"minimum":15.0},{"type":"null"}],"title":"Everyseconds"}},"type":"object","title":"VisionBody"},"WarehouseReceiveBody":{"properties":{"received":{"type":"boolean","title":"Received","default":true}},"type":"object","title":"WarehouseReceiveBody"},"WebhookRequest":{"properties":{"url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Url"}},"type":"object","title":"WebhookRequest"},"app__routes__aahaa__ExecuteRequest":{"properties":{"confirm":{"type":"boolean","title":"Confirm","description":"Required for human-contact / money actions","default":false},"playerRef":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Playerref"},"lat":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Lat","description":"Geo-gate re-check position"},"lng":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Lng"},"email":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Email","description":"push/nudge destination"},"answers":{"anyOf":[{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array"},{"type":"null"}],"title":"Answers","description":"fortune/quiz answers"},"resultId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Resultid","description":"Quizverse result id"},"weekId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Weekid"},"eventId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Eventid"},"amountUsd":{"anyOf":[{"type":"number","maximum":1000.0,"minimum":0.0},{"type":"null"}],"title":"Amountusd"},"startsAt":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Startsat"},"shareText":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Sharetext"},"phone":{"anyOf":[{"type":"string","maxLength":24},{"type":"null"}],"title":"Phone"}},"type":"object","title":"ExecuteRequest"},"app__routes__aahaa__PlanRequest":{"properties":{"machineNo":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Machineno"},"playerRef":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Playerref","description":"Who the aha is for"},"lat":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Lat","description":"Player location"},"lng":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Lng"},"surface":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Surface","description":"aahaa surface id"},"cohortLabel":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Cohortlabel"},"rewardKind":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Rewardkind"},"productName":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Productname","description":"Cross-sell anchor"},"moment":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Moment","description":"Share moment (win/visit)"},"phone":{"anyOf":[{"type":"string","maxLength":24},{"type":"null"}],"title":"Phone","description":"Voice companion target"},"certCompleted":{"type":"boolean","title":"Certcompleted","description":"Player finished the cert (perk gate input)","default":false},"deterministic":{"type":"boolean","title":"Deterministic","description":"Skip LLM phrasing (evals/CI)","default":false}},"type":"object","title":"PlanRequest"},"app__routes__agent_releases__ReleaseIn":{"properties":{"version":{"type":"string","title":"Version","description":"Dotted-numeric agent version, e.g. 1.4.0"},"sha256":{"type":"string","title":"Sha256","description":"Lowercase hex digest of the tarball"},"size":{"type":"integer","title":"Size","description":"Tarball size in bytes","default":0},"url":{"type":"string","title":"Url","description":"HTTPS artifact URL under the fleet's publish prefix"},"signature":{"type":"string","title":"Signature","description":"Base64 RSA-PKCS1v15-SHA256 over the release record"},"sequence":{"type":"integer","title":"Sequence","description":"Publish order; derived when omitted","default":0},"migration":{"type":"boolean","title":"Migration","description":"True when this release changes on-disk state, so cabinets below it may not skip over it on the way to a later one","default":false},"minFrom":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Minfrom","description":"Lowest version that may install this one directly"}},"type":"object","required":["version","sha256","url","signature"],"title":"ReleaseIn"},"app__routes__engagement_metrics__EventIn":{"properties":{"type":{"type":"string","title":"Type"},"at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"At"},"props":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Props"}},"type":"object","required":["type"],"title":"EventIn"},"app__routes__machine_network__RevealIn":{"properties":{"password":{"type":"string","title":"Password"}},"type":"object","required":["password"],"title":"RevealIn"},"app__routes__operator_ledger__ReleaseIn":{"properties":{"machineNo":{"type":"string","title":"Machineno"},"reason":{"type":"string","title":"Reason","default":""}},"type":"object","required":["machineNo"],"title":"ReleaseIn"},"app__routes__operator_os__ExecuteRequest":{"properties":{"confirm":{"type":"boolean","title":"Confirm","description":"Required for destructive/costly actions","default":false},"tech":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Tech","description":"Assignee for dispatch/job actions"}},"type":"object","title":"ExecuteRequest"},"app__routes__operator_os__PlanRequest":{"properties":{"lat":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Lat","description":"Tech/operator location"},"lng":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Lng"},"deterministic":{"type":"boolean","title":"Deterministic","description":"Skip LLM phrasing (evals/CI)","default":false}},"type":"object","title":"PlanRequest"},"app__routes__operator_reads__SubscribeRequest":{"properties":{"operatorEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operatoremail","description":"Admin only: act on this operator"}},"type":"object","title":"SubscribeRequest"},"app__routes__operator_workspace__EventIn":{"properties":{"title":{"type":"string","title":"Title"},"on":{"type":"string","title":"On"},"kind":{"type":"string","title":"Kind","default":"other"},"detail":{"type":"string","title":"Detail","default":""},"venueId":{"type":"string","title":"Venueid","default":""},"machineNo":{"type":"string","title":"Machineno","default":""},"memberId":{"type":"string","title":"Memberid","default":""}},"type":"object","required":["title","on"],"title":"EventIn"},"app__routes__operator_workspace__RevealIn":{"properties":{"reason":{"type":"string","title":"Reason","default":""}},"type":"object","title":"RevealIn"},"app__routes__orders__RefundRequest":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"external":{"type":"boolean","title":"External","default":false},"externalReference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Externalreference"}},"type":"object","title":"RefundRequest"},"app__routes__subscriptions__SubscribeRequest":{"properties":{"machineNos":{"items":{"type":"string"},"type":"array","title":"Machinenos"},"type":{"type":"string","title":"Type","default":"Monthly"},"checkout":{"type":"boolean","title":"Checkout","default":false},"successUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Successurl"},"cancelUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancelurl"}},"type":"object","required":["machineNos"],"title":"SubscribeRequest"},"app__routes__superadmin_money__RefundRequest":{"properties":{"amountUsd":{"type":"number","title":"Amountusd"},"reason":{"type":"string","title":"Reason"},"confirm":{"type":"boolean","title":"Confirm","default":false}},"type":"object","required":["amountUsd","reason"],"title":"RefundRequest"},"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","example":200},"message":{"type":"string","example":"success"},"data":{"description":"Payload; null on errors."}}}},"securitySchemes":{"X-API-Key":{"type":"apiKey","name":"X-API-Key","in":"header"},"OAuth2":{"type":"oauth2","flows":{"clientCredentials":{"tokenUrl":"https://api.kiosk-x.ai/oauth/token","scopes":{"machines:read":"machines:read","machines:write":"machines:write","inventory:read":"inventory:read","inventory:write":"inventory:write","orders:read":"orders:read","orders:write":"orders:write","commands:read":"commands:read","commands:write":"commands:write","ads:read":"ads:read","ads:write":"ads:write","machines:build":"machines:build","accounts:admin":"accounts:admin"}}}}}}}