API overview
The Miseline API is the same REST API the web and mobile apps run on — everything the product does is reachable over HTTPS with JSON. This reference covers authentication, conventions, and the core resource families, with real request and response examples.
API access (API keys) and webhooks are available on Pro and Enterprise plans.
Base URL
https://miseline.keyedsystems.com/api
All paths in this reference are relative to the base URL. Requests and responses are JSON (Content-Type: application/json) unless noted; media uploads use raw binary bodies.
Authentication at a glance
| Credential | Header | Used for |
|---|---|---|
| Access token (JWT) | Authorization: Bearer <token> | The full API, as a signed-in user |
API key (mk_live_…) | x-api-key: <key> | Server-to-server ingest (currently the HL7 ADT endpoint) |
Device token (mdt_…) | x-device-token: <token> | Board and device endpoints only |
| Public tokens | in the URL | Surveys, shared quotes/invoices/reports — no auth at all |
See Authentication for the session flow and Device tokens, public links & ingest for the rest.
Organization scoping
Almost every resource lives under an organization:
GET /orgs/{orgId}/recipes
Your organization ids come from your session's membership list (see Authentication). Every request is checked against your membership in that organization and your role's permissions — you can never read or write another organization's data, and ids from other organizations behave exactly like ids that don't exist (404).
Errors
Every error is JSON with the same shape:
{
"error": "Recipe not found",
"statusCode": 404
}
| Status | Meaning |
|---|---|
| 400 | Validation failed — the message says which field |
| 401 | Missing or invalid credentials |
| 402 | Feature not in your plan (see below) |
| 403 | Authenticated, but your role or permissions don't allow it |
| 404 | Not found — including anything outside your organization |
| 409 | Conflict (e.g. duplicate email on registration) |
| 422 | Understood but not processable (e.g. insufficient points, unparseable HL7) |
| 429 | Rate limited — a Retry-After header says when to retry (seconds) |
| 5xx | Something went wrong on our side |
The paywall shape (402)
When an endpoint needs a feature your plan doesn't include, the response is a 402 with machine-readable fields naming the feature and the plan that unlocks it:
{
"error": "Social publishing is a Enterprise feature — upgrade the plan in Settings → Billing to unlock it.",
"statusCode": 402,
"feature": "social_publishing",
"requiredPlan": "Enterprise"
}
Site and device caps use the same shape with feature set to site_limit or device_limit. Treat any 402 as "show an upgrade path", not as a failure.
Timestamps and dates
- Timestamps are returned as PostgreSQL-style strings with an explicit offset:
"2026-07-12 00:40:10.126421+00"(note the space, not aT). Parse them with a real date parser; don't compare them lexically against ISO strings. - Calendar dates are plain
"YYYY-MM-DD"strings. - "Today" for a site is computed in the site's timezone, not UTC.
Ids
All ids are UUIDs. Ids in this reference's examples are real-shaped but sanitized.
Rate limits
The general authenticated API is not rate limited. Credential and public endpoints are:
| Surface | Limit |
|---|---|
| Sign-in | 5 failed attempts per email+IP, then a 15-minute lock |
| Registration | 3 accounts per IP per hour |
| Device pairing-code claims | 10 per IP per minute |
| Public survey views/submissions | 30 per IP per minute |
| Public inspection-report views | 30 per IP per minute |
| Public storefront checkout | 10 per IP per minute |
| Public lead and support forms | 5 per IP per minute |
429 responses carry a Retry-After header in seconds.
Compliance, observations, and scan endpoints
These families are documented here at overview level (they don't have a full resource page yet). All are organization-scoped and follow every convention above.
GET /orgs/{orgId}/compliance/library/search ?q&framework&license&adopted&limit
GET /orgs/{orgId}/compliance/library/autocomplete ?q
GET /orgs/{orgId}/compliance/library/control/{controlId}
POST /orgs/{orgId}/compliance/audit-presets/{presetKey}
GET /orgs/{orgId}/observations/search ?q&category&limit
GET /orgs/{orgId}/observations/autocomplete ?q
GET /orgs/{orgId}/observations/{observationId}
POST /orgs/{orgId}/observation-captures
GET /orgs/{orgId}/observation-captures ?siteId&assetId&spaceId&evidenced&since&…
DELETE /orgs/{orgId}/observation-captures/{id}
POST /orgs/{orgId}/ai/field-guidance
GET /orgs/{orgId}/tags ?siteId
GET /orgs/{orgId}/scan/{tagCode}
- Standards library — ranked search across every built-in framework pack (titles, citations including fragments like
F812, standard text, authority), merged with your organization's adoption and control state. The control detail endpoint returns the standard's text with its license provenance, your state, linked policies, and recent evidence. - Audit presets —
POST …/audit-presets/{presetKey}creates a draft audit template from one of the seven curated cross-framework presets; the response carries the newtemplateId. - Observation captures —
POSTrecords one field capture. Supply your own UUIDidto make the call idempotent: replaying the same id returns the existing row and never repeats the fan-out. A first insert fans out into control-evidence rows per the condition's control mappings and raises at most one draft finding (statusproposed) when a deficiency was observed; the response includes theexpansion.DELETEundoes a capture: it removes the evidence rows, and removes the draft finding only while it is still `proposed` — reviewed findings are kept, and the response'sreversedblock says which happened. - Field guidance —
POST …/ai/field-guidanceresolves evidence expectations for a set of controls, an observation, or a template item. It always answers200with the static guidance; the optional AI narrative reportsai.availablerather than failing when AI isn't configured. - Tags and scan —
GET …/tagslists every scannable target (equipment and spaces) with its tag code, for label printing.GET …/scan/{tagCode}resolves a tag into the target plus a role-awareactionslist and context (open tasks, sensors, recent captures); unauthenticated calls return401with ascan: {tagCode, orgId}block so clients can resume the scan after sign-in — see scan deep links.
Reading this reference
- Authentication — sessions, refresh rotation, memberships, roles, API keys
- Organizations, sites & people
- Culinary — ingredients, recipes, menus, signoffs
- Kitchen operations — forecasts, production, tasks, supply
- Clinical — residents, diet orders, tray line, intake
- Commerce — dining room, meal plans, POS, catering
- Webhooks — signed outbound events
- Device tokens, public links & ingest — boards, surveys, share links, HL7 ADT