All API reference pages

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

CredentialHeaderUsed 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 tokensin the URLSurveys, 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
}
StatusMeaning
400Validation failed — the message says which field
401Missing or invalid credentials
402Feature not in your plan (see below)
403Authenticated, but your role or permissions don't allow it
404Not found — including anything outside your organization
409Conflict (e.g. duplicate email on registration)
422Understood but not processable (e.g. insufficient points, unparseable HL7)
429Rate limited — a Retry-After header says when to retry (seconds)
5xxSomething 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 a T). 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:

SurfaceLimit
Sign-in5 failed attempts per email+IP, then a 15-minute lock
Registration3 accounts per IP per hour
Device pairing-code claims10 per IP per minute
Public survey views/submissions30 per IP per minute
Public inspection-report views30 per IP per minute
Public storefront checkout10 per IP per minute
Public lead and support forms5 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 presetsPOST …/audit-presets/{presetKey} creates a draft audit template from one of the seven curated cross-framework presets; the response carries the new templateId.
  • Observation capturesPOST records one field capture. Supply your own UUID id to 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 (status proposed) when a deficiency was observed; the response includes the expansion. DELETE undoes 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's reversed block says which happened.
  • Field guidancePOST …/ai/field-guidance resolves evidence expectations for a set of controls, an observation, or a template item. It always answers 200 with the static guidance; the optional AI narrative reports ai.available rather than failing when AI isn't configured.
  • Tags and scanGET …/tags lists 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-aware actions list and context (open tasks, sensors, recent captures); unauthenticated calls return 401 with a scan: {tagCode, orgId} block so clients can resume the scan after sign-in — see scan deep links.

Reading this reference