Information
- OpenAPI version:
3.1.0
Send-only alarm ingest API for DIY smart homes.
The OpenAlarm core API is the send-only endpoint your smart home calls to arm, disarm, trigger, and fire panic buttons. OpenAlarm is a messenger, not a monitor - these calls send texts, calls, and email to the contacts you have chosen; they never reach professional monitoring.
Every request carries an account-level API key, sent either as X-API-Key: <key> (canonical)
or Authorization: Bearer <key> (equivalent - the two are OR-ed). The key authorizes the alarm
actions below plus a small read-only integration surface - it cannot change
configuration or access your account. It opens the gate; it does not own data. See the
Authentication guide.
Every endpoint is a plain GET - the URL is the whole call and there is no request body to
assemble, so a Home Assistant rest_command, a UniFi Protect webhook, or a one-line curl just
hits a path. Because the API key travels in a header - never in the URL - a scanned or prefetched
URL carries no key and cannot fire an alarm.
POST is reserved for the future - for endpoints that accept a request body - and is not used
by the current ingest endpoints.
Each alarm has five modes - Home, Away, Night, Vacation, and Disarmed.
Disarmed has its own endpoint. You do not arm to it - there is no arm/disarmed - you call
disarm. It binds no escalation policy, so there is no trigger/disarmed either. It does carry
its own settings, such as whether disarming clears an incident that is already open.
Arming and triggering come as matched pairs, and two bare shortcuts keep the common paths trivial:
arm with no mode re-arms the currently armed mode when there is one; from Disarmed
(or if the armed mode was since deleted) it arms Away, the most conservative posture.trigger with no mode fires the currently armed mode’s policy, falling back to Away
when the alarm is Disarmed or the armed mode no longer exists. Naming a mode explicitly never
falls back - if you asked for a specific policy, firing a different one is worse than firing
none.Disarming returns the alarm to Disarmed and clears the armed mode with it, so a later bare arm
returns to Away rather than resurrecting the mode you last used.
An alarm moves on two independent axes, and only one of them is arming.
arm and disarm change
it.trigger opens one; clear, a configured disarm, or the 24-hour auto-close ends it.The two never interact. A trigger does not disarm your alarm, and clearing an incident does not either - an alarm armed Away when it fired is still armed Away while the incident runs and after it is cleared.
A trigger always fires, armed or not. Arming does not gate it - OpenAlarm sits downstream of
whatever you already run, and that system has already decided this is worth alerting about.
Arming answers a different question: which policy a bare trigger runs.
So a source that cannot arm needs no special setup. A UniFi Protect camera fires one fixed
webhook and can never call arm, so its alarm sits in Disarmed forever; its bare trigger simply
runs the Away policy.
If you would rather OpenAlarm did check, each alarm has an optional Only trigger when armed setting, off by default. See the Arming guide.
Panic buttons are never armed, so none of this applies to them. See the Arming guide.
Every endpoint returns 202 Accepted. There is no 200 anywhere on this API - arming,
disarming, triggering, and clearing all answer with the same code, so a caller never branches on
which 2xx came back. The call has been accepted and will be applied; for a trigger, alerts go
out after the false-alarm cancellation window, so nothing has reached your contacts at the moment
the response arrives.
Every response uses the same four-field envelope:
{
"error": false,
"message": null,
"traceId": "8f14e45f-ea0d-4a1b-9f2c-6b3d70c5e881",
"data": {
"environment": "live",
"location": { "id": "2c9wvhrq52k5refhtvmmr0f8yjz5j9e9", "name": "Home" }
}
}
error is the outcome boolean. message is human-readable and null on success. traceId
identifies that one call - worth logging, and worth quoting if you report a problem. data
carries the payload: environment, and the location the alarm or panic button belongs to.
There is no status field: the HTTP status is already on the response, and echoing it into
the body would create two sources of truth that can disagree.
401 - the API key is missing or invalid. The one response that does not use the
envelope - it returns only a message and no traceId.404 - the alarm or panic button is not available to fire. Four cases, deliberately
indistinguishable - see the 404 reference on any operation page.Every alarm and panic button is either live or test. You choose which when you create it, and you can change it at any time in the console - per alarm, or for a whole location at once.
A test is fully silent. Nobody is contacted - not your contacts, not you. The escalation policy runs on its real timeline: levels fire at their true delays, repeats repeat, and the incident ends the same three ways a live one does. Every contact the chain reaches is recorded with the delivery marked suppressed - who, on which channel, at the level and the time they would have been contacted - so a test reads as the real thing that did not happen, not as a failure. A contact who could not have been alerted anyway is recorded as skipped, with the reason. See the Test Mode guide for the full picture, including how test triggers look to connected systems like Home Assistant.
Live or test belongs to the alarm, never to the call. There is no query parameter and no per-call override; configuration lives in the console, not in the request. A flag deciding whether real people get woken up has no business being optional URL syntax, and a UniFi Protect webhook could not pass one anyway.
Every 2xx reports which one actually ran, as data.environment - so an automation that
believes it is live can confirm it rather than assume it.
The account-level API key - oa_ followed by 64 characters. The canonical form.
Security scheme type: apiKey
Header parameter name: X-API-Key
The same account-level API key, sent as a bearer token. Equivalent to X-API-Key.
Security scheme type: http