All API reference pages

Authentication

The API authenticates people with short-lived access tokens (JWTs) plus rotating refresh tokens, and servers with org-scoped API keys. Boards and public links use their own credentials — see Device tokens, public links & ingest.

Register

POST /auth/register
{
  "name": "Alex Rivera",
  "email": "alex@example.com",
  "password": "a-strong-password",
  "orgName": "Riverbend Dining"
}

Creates the user, and — when orgName is given — a new organization with the caller as owner, started on a 30-day Pro trial. Returns 201 with a full session (below). Registering an email that already exists returns 409. Limited to 3 registrations per IP per hour.

Log in

POST /auth/login
{ "email": "alex@example.com", "password": "a-strong-password" }

Or with curl:

curl -X POST https://miseline.keyedsystems.com/api/auth/login \
  -H "content-type: application/json" \
  -d '{"email":"alex@example.com","password":"a-strong-password"}'

Successful register/login/refresh responses share one shape:

{
  "accessToken": "eyJhbGciOiJIUzI1NiJ9...",
  "refreshToken": "wStB4nZk8mQ2vX...",
  "expiresIn": 900,
  "user": {
    "id": "7f3a2c48-1b9e-4d2a-9c67-2f8e5a0d1b23",
    "email": "alex@example.com",
    "name": "Alex Rivera",
    "memberships": [
      {
        "orgId": "05b955b6-c196-4e31-a383-4251dee16f8a",
        "orgName": "Riverbend Dining",
        "role": "owner",
        "siteIds": []
      }
    ]
  }
}
  • accessToken — a JWT, valid for 15 minutes (expiresIn is seconds). Send it on every request: Authorization: Bearer <accessToken>.
  • refreshToken — valid for 30 days, single-use (see below).
  • memberships — every organization the user belongs to, with their role and site scoping (siteIds: [] means all sites). Use orgId to build resource paths.

Five failed sign-in attempts for the same email+IP within 15 minutes locks that combination for 15 minutes (429 with Retry-After).

Refresh

POST /auth/refresh
{ "refreshToken": "wStB4nZk8mQ2vX..." }

Returns a fresh session and a new refresh token — the presented one is consumed. Store the replacement every time; reusing a consumed, expired, or revoked token returns 401. Changing the password revokes all outstanding refresh tokens (the change-password response includes a fresh session so the current client stays signed in).

Who am I

GET /auth/me

Returns the user object (with current memberships) for the presented access token — useful at app start and after membership changes.

Roles and permissions

A membership's role decides what the token can do in that organization. Roles are ranked — each includes everything below it:

owner > admin > manager > inspector (staff) > viewer

Writes check a named permission with a minimum role — for example creating recipes needs manageCulinary (manager+), inviting users needs manageUsers (admin+), and webhooks/API keys need manageOrg (owner). A role that's too low gets 403. Some clinical decisions additionally require a credential on the membership (e.g. diet signoffs require rd) regardless of rank. Site-scoped memberships (siteIds non-empty) are limited to those sites' data on site-scoped resources.

API keys

API keys are org-scoped server credentials for integrations — currently they authenticate the HL7 ADT ingest endpoint; everything else in the API expects a user session. Keys are available on Pro and Enterprise plans and managed by owners (in the app under Billing & plan → Developer, or via the API):

POST /orgs/{orgId}/api-keys
{ "name": "EHR interface" }
{
  "id": "34c2927b-7efd-4725-ba1c-f67147787680",
  "name": "EHR interface",
  "key": "mk_live_mX9nVuFoKP_oEQrx7aG0Prfihgrdoo3W",
  "note": "Store this now — it is shown once. Read-only scope; use header x-api-key."
}

The full key is returned once and stored hashed. Present it as the x-api-key header. GET /orgs/{orgId}/api-keys lists keys (id, name, prefix, last used, active); DELETE /orgs/{orgId}/api-keys/{id} revokes — revoked keys fail with 401 immediately.

Good citizenship

  • Refresh proactively rather than retrying 401s in a loop.
  • Scope one API key per integration and name it honestly — lastUsedAt and the prefix are your audit trail.
  • Treat refresh tokens and API keys like passwords: server-side storage only, never in client code or logs.