MusterHub

MusterHub Integrations API

API documentation for connecting control room, training and learning systems to MusterHub. Review the endpoints, access scopes and data formats with the team building your integration.

Authentication

All integration endpoints use a service-scoped API key passed as the X-Api-Key request header. Keys are separate from user accounts. They belong to your service, not to any individual.

X-Api-Key: mh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key management

  • Generated in your MusterHub admin portal under Settings > API Keys
  • Scoped to specific capabilities: a control room key cannot import training records
  • Optionally time-limited with an expiry date
  • Revocable at any time without affecting other integrations or users
  • The plain-text key is shown once on creation only, so store it securely immediately
  • Only a one-way hash is ever stored by MusterHub
Tip Issue a separate key per integration system. If a key is compromised you can revoke just that one without disrupting anything else.

Scopes

When generating a key you choose which scopes to grant. A single key can hold multiple scopes, or you can issue one key per system.

ScopeWhat it unlocks
Control Room Push vehicle availability, trigger operational alerts, create control room events
Incident Import Upsert incident and callout records
Course Import Sync course catalogue and attendee lists from an LMS
Training Import Sync training records and qualifications from a TMS
Directory Export Read-only export of your service's groups, locations, people and vehicles. Payload keys retain the existing API terminology.
Notification Send Send a push notification to one of your service's users

Control Room API

Real-time integration for mobilisation and CAD systems. These endpoints are designed for low-latency pushes directly from your control room. No polling, no scheduled jobs required.

An external system needs to send authenticated HTTPS requests using the formats below. Check its API access, mapping and integration work with its supplier; the ability to send JSON does not establish a tested connector.

Requires: Control Room scope

Update vehicle status

Push a vehicle’s availability by its configured callsign. The API uses the existing term appliance. The examples below use fire and rescue terminology; keep the endpoint names and JSON keys exactly as documented.

POST /api/control-room/appliance-status

Request body

{ "callsign": "KV57A", "status": "Available", "crewOnBoard": 4, "crewRequired": 5 }
FieldTypeRequiredNotes
callsignstringYesMust match the callsign configured in MusterHub
statusstringYesAvailable, Unavailable, Responding, AtScene, Returning
crewOnBoardintegerNoCurrent crew count
crewRequiredintegerNoFull crew requirement for this appliance

Response (200)

{ "callsign": "KV57A", "status": "Available", "crewOnBoard": 4, "crewRequired": 5, "updatedAtUtc": "2026-07-02T08:30:00Z" }

Trigger a turnout alert

Send an operational alert from your control room or mobilisation system. Recipients depend on the target, their preferences and duty records. Critical alerts on iOS also depend on permissions and device settings; check delivery on the devices your service uses before operational rollout.

POST /api/control-room/turnout

Request body

{ "stationCode": "KV57", "title": "House fire, persons reported", "description": "14 High Street, Tavistock. 3-pump attendance.", "incidentReference": "2026-INC-04821", "targetEmployeeNumber": "5893", "isTest": false }
FieldTypeRequiredNotes
stationCodestringYesStation code as configured in MusterHub (e.g. KV57)
titlestringYesAlert headline, shown on the device lock screen
descriptionstringNoAdditional detail shown in the notification body
incidentReferencestringNoLinks the alert to an existing incident record if the reference matches
targetUserIdUUIDNoOmit to broadcast to all station members; supply to alert a single member only
targetEmployeeNumberstringNoAlternative to targetUserId: alert the single member with this employee number. Rejected if the number matches no one or more than one person
isTestbooleanNoMarks as a test: prefixes title with [TEST] and does not send as a critical notification

Returns the created turnout alert object (200), including its id which can be used to track responses via the app.

On-call filtering Members who have enabled the "only alert me when on call" preference in the app will only receive this notification if they have an active on-call rota window at the time of the request. A per-station buffer (configurable in the admin portal under Stations) is subtracted from the rota start time: a 5-minute buffer on an 08:00 shift means the member receives alerts from 07:55. This preference is filtered server-side. Members who have not enabled it can receive alerts outside their on-call window.

Create a control room event

Push a scheduled event into MusterHub from an external system, for example a planned exercise or training burn from a mobilisation system. The event is visible to all members across your service.

POST /api/control-room/events

Request body

{ "title": "Scheduled exercise: breathing apparatus", "description": "Quarterly BA drill at Tavistock station.", "startAtUtc": "2026-07-10T09:00:00Z", "endAtUtc": "2026-07-10T12:00:00Z", "location": "KV57 Tavistock Fire Station" }
FieldTypeRequired
titlestringYes
descriptionstringYes
startAtUtcISO 8601 datetimeYes
endAtUtcISO 8601 datetimeYes
locationstringNo

Incident Import

Batch import incident and callout records from your mobilisation system. Records are matched by reference: re-posting the same reference updates the existing record rather than creating a duplicate. Safe to run as a scheduled sync.

Requires: Incident Import scope

POST /api/integrations/incidents

Request body

{ "incidents": [ { "reference": "2026-INC-04821", "incidentType": "House fire", "description": "14 High Street, Tavistock. Persons reported.", "startedAtUtc": "2026-07-02T08:14:00Z", "endedAtUtc": "2026-07-02T10:42:00Z", "appliancesAttended": ["KV57A", "KV57B"], "stationCode": "KV57" } ] }
FieldTypeRequiredNotes
referencestringYesUnique reference from your mobilisation system, used for idempotent matching
incidentTypestringYesFree-text, e.g. House fire, RTC, Flooding
descriptionstringNo
startedAtUtcISO 8601 datetimeYes
endedAtUtcISO 8601 datetimeNoCan be omitted and updated in a later sync once the incident is closed
appliancesAttendedstring arrayNoList of callsigns that attended
stationCodestringNoLinks the incident to a station; must match a station code in MusterHub

Response (200)

{ "created": 1, "updated": 0, "warnings": [] }

Warnings are returned for skippable issues such as an unrecognised station code. The rest of the batch still processes, and warnings do not cause a failure response.

Course Import

Sync your course catalogue from an external learning management system. Courses are matched by externalId so re-running the sync updates rather than duplicates. Attendees are matched to MusterHub members by employee number first, then email.

Compatible systems include Moodle, TalentLMS and Zoho Learn.

Requires: Course Import scope

POST /api/integrations/courses

Request body

{ "courses": [ { "externalId": "LMS-COURSE-9871", "title": "Incident Command Level 2", "startDate": "2026-08-14", "endDate": "2026-08-15", "startTime": "09:00:00", "endTime": "17:00:00", "venue": "Devon & Somerset Fire HQ, Exeter", "facilitator": "Station Manager A. Hughes", "additionalDetails": "Bring your Level 1 certificate. PPE provided.", "resources": [ { "resourceDisplayName": "Pre-course reading", "resourceLink": "https://your-lms.example.com/ic2-prereading" } ], "attendees": [ { "employeeNumber": "PR04821" }, { "email": "j.smith@example-brigade.gov.uk" } ] } ] }
FieldTypeRequiredNotes
externalIdstringYesYour LMS's unique ID, used for idempotent matching on re-sync
titlestringYes
startDate / endDatedate (YYYY-MM-DD)Yes
startTime / endTimetime (HH:MM:SS)Yes
venuestringYes
facilitatorstringYes
additionalDetailsstringNo
resourcesarrayNoPre-course materials: each needs resourceDisplayName and resourceLink
attendeesarrayNoEach attendee needs at least one of employeeNumber or email

Response (200)

{ "created": 1, "updated": 0, "warnings": [ "Course 'IC Level 2' (LMS-COURSE-9871): no user found for attendee (employee number 'PR09999', email '')." ] }

Unmatched attendees generate a warning but do not fail the import. The course itself is still created or updated.

Training & Qualifications Import

Sync training records and qualifications from your training management system. Members are matched by externalRef first, then by employeeNumber. If a member cannot be matched, an unlinked record is created and can be manually linked later in the admin portal.

Qualifications within each record are matched by their own externalRef, which is strongly recommended to prevent duplicates on re-sync.

Compatible with any Training Management System that can export member records via REST API.

Requires: Training Import scope

POST /api/integrations/training

Request body

{ "records": [ { "externalRef": "TMS-MEMBER-1042", "employeeNumber": "PR04821", "memberName": "James Smith", "qualifications": [ { "externalRef": "TMS-QUAL-55001", "name": "Breathing Apparatus Wearers", "category": "Operational", "achievedDate": "2023-04-12", "expiryDate": "2026-04-12", "type": "Practical", "renewalMonths": 36 }, { "externalRef": "TMS-QUAL-55042", "name": "Fire Safety Awareness", "category": "Compliance", "achievedDate": "2025-01-08", "type": "ELearning", "eLearningUrl": "https://your-lms.example.com/fire-safety-awareness" } ] } ] }

Member record fields

FieldTypeRequiredNotes
externalRefstringNoRecommended: your TMS's unique ID for this member, used for matching on subsequent syncs
employeeNumberstringNoMember's employee number in MusterHub (each service can label this differently in its portal, e.g. PR number)
memberNamestringYes
qualificationsarrayYesCan be an empty array

Qualification fields

FieldTypeRequiredNotes
externalRefstringNoStrongly recommended: prevents duplicate qualifications on re-sync
namestringYes
categorystringYesFree-text grouping, e.g. Operational, Compliance, Leadership
achievedDatedate (YYYY-MM-DD)Yes
expiryDatedate (YYYY-MM-DD)No
typestringNoPractical (default) or ELearning
renewalMonthsintegerNoUsed to calculate the next renewal date and surface expiry warnings
eLearningUrlstringNoDisplayed as a link to the member for ELearning type qualifications

Response (200)

{ "recordsCreated": 1, "recordsUpdated": 0, "qualificationsCreated": 2, "qualificationsUpdated": 0, "warnings": [] }

Companion products

These two endpoints exist specifically for MusterHub's own companion products (currently MusterHub Rota, Skills and Command) that plug into your organisation's data without holding a copy of it. The same API key mechanism applies: generate a key with the scope the companion product needs.

Directory export

Read-only snapshot of your service's organisational structure: groups, stations, personnel and their station memberships, and appliances. Intended for a companion product's own initial import or a periodic re-sync, not for polling.

Requires: Directory Export scope

GET /api/integrations/directory

Response (200)

{ "serviceId": "5a2e...", "serviceName": "Devon & Somerset Fire and Rescue", "groups": [ { "id": "...", "name": "Exeter Group" } ], "stations": [ { "id": "...", "code": "KV57", "name": "Tavistock", "groupId": "..." } ], "users": [ { "id": "...", "fullName": "James Smith", "rank": "Firefighter", "employeeNumber": "PR04821", "stations": [ { "stationId": "...", "isHome": true } ] } ], "appliances": [ { "id": "...", "callsign": "KV57A", "description": "Pump", "stationId": "..." } ] }
Deliberately minimal This export excludes email addresses and notification preferences. It gives a companion product identity, structure and membership, nothing more, so it can match people to your existing MusterHub roster without becoming a second copy of contact data.

Notification relay

Lets a companion product send an ordinary push notification to one of your service's users through MusterHub's own push pipeline, without ever holding device tokens itself. For example, MusterHub Rota uses this to alert someone their shift swap was approved, and Skills uses it to nudge someone whose evidence has just been signed off.

Requires: Notification Send scope

POST /api/integrations/notifications

Request body

{ "userId": "5a2e...", "title": "Shift swap approved", "body": "Your swap with J. Smith for Saturday's shift has been approved.", "navigationType": "rota", "navigationId": null }
FieldTypeRequiredNotes
userIdUUIDYesMust belong to the same service your API key is scoped to; otherwise returns 404
titlestringYes
bodystringYes
navigationTypestringNoTells the app which screen to open when the notification is tapped
navigationIdstringNoOptional ID passed alongside navigationType, e.g. a specific record to open

Response (200)

{ "devicesNotified": 2 }
Ordinary, not critical This endpoint always sends a normal push notification. It cannot be used to trigger a critical, Do-Not-Disturb-bypassing alert: that stays exclusive to MusterHub's own turnout system.

Verifying MusterHub Tokens

When a signed-in MusterHub user opens a companion product product, MusterHub can hand it a short-lived access token so the person doesn't have to sign in a second time. The companion product validates that token itself, entirely offline: it never has to call back into MusterHub or hold a shared secret.

GET /.well-known/jwks.json

This endpoint is public and unauthenticated. It publishes MusterHub's current RSA public key in standard JWKS format, which any JWT library can use directly to verify a token's signature.

What to check

Claim / propertyExpected value
SignatureValid against the current key published at /.well-known/jwks.json
issMusterHub
audMusterHubApp
expAccess tokens are short-lived (30 minutes) — reject anything expired, don't extend it yourself
subThe MusterHub user's ID
org_idThe user's MusterHub service (organisation) ID — scope everything you do to this
entitlementsArray of bolt-on module codes enabled for the whole organisation (e.g. rota, skills, command)
module_adminArray of module codes this specific person administers, a subset of what your service has enabled
org_id is the trust boundary Always scope the request to org_id, not just a valid signature. A validly-signed token from a different MusterHub organisation should never be treated as authorised for yours.

Error handling

All endpoints return standard HTTP status codes. Errors return a plain-text body describing the issue.

CodeMeaning
200Success. Check the warnings array in the response body for partial issues that did not block the overall request.
400Bad request: a required field is missing or a value is invalid (e.g. an unknown appliance status string).
401Unauthorised: the X-Api-Key header is missing, the key is invalid or expired, or the key does not have the required scope for this endpoint.
404Not found: a referenced entity does not exist in MusterHub (e.g. an unknown callsign or station code passed as a required field).
Warnings vs. errors Import endpoints (incidents, courses, training) distinguish between hard errors and warnings. A hard error (4xx) means nothing was processed. A warning means one item in the batch was skipped, for example, an unrecognised station code on an incident, or an attendee whose email doesn't match any member. The rest of the batch still succeeds and the response is still 200.

Getting started

  1. Sign in to your MusterHub admin portal and go to Settings > API Keys.
  2. Click Generate new key, give it a name (e.g. "Capita Parity"), and select the scopes you need.
  3. Copy the key immediately: it is shown once only and cannot be retrieved afterwards.
  4. Confirm your service’s API base URL with your administrator, then configure your external system to send requests there with the X-Api-Key: <your-key> header.
  5. Send a test request with "isTest": true (for turnout) or a single record (for imports) and verify the response.
Base URL Use the base URL of the instance approved for your service. Do not send operational data to a generic or example host. The endpoint paths on this page are relative to that approved URL.

Need help?

If your system isn't listed, you're not sure which scope you need, or you'd like us to help configure the integration, get in touch: