Authentication
Every request to the OpenAlarm Core API (api.openalarm.io) is authenticated with an account-level
API key.
Generating an API Key
Section titled “Generating an API Key”In the OpenAlarm console, go to Developers → API Keys, click New API Key, and create the key. Keys can be scoped to specific alarms and panic buttons - the right shape for a key that lives in one webhook config.
Every key starts with the oa_ prefix followed by 64 characters - the prefix is what tells a key
apart from a resource ID at a glance:
oa_m9s346q3d25vt4f5v37e3s3e28jt97kb6cq643dzvmxxqkfbf5kznwj47tan9zt2The key authorizes the alarm actions (arm, disarm, trigger, clear, panic) plus a small read-only integration surface - the inventory and live state the official Home Assistant integration is built on, fenced to whatever the key can fire. It cannot change configuration or access your account.
Sending the API Key
Section titled “Sending the API Key”Send the key on every request, one of two equivalent ways. X-API-Key is the canonical form; an
Authorization: Bearer token is also accepted.
Using X-API-Key
Section titled “Using X-API-Key”X-API-Key: oa_m9s346q3d25vt4f5v37e3s3e28jt97kb6cq643dzvmxxqkfbf5kznwj47tan9zt2curl \ -H "X-API-Key: oa_m9s346q3d25vt4f5v37e3s3e28jt97kb6cq643dzvmxxqkfbf5kznwj47tan9zt2" \ https://api.openalarm.io/v1/alarm/k7m3x9q2f8d4w1b5n6p0r3t7v2x5z9c4/triggerUsing a Bearer Token
Section titled “Using a Bearer Token”Send the key in the Authorization header as a bearer token - the word Bearer, a single space,
then your key:
Authorization: Bearer oa_m9s346q3d25vt4f5v37e3s3e28jt97kb6cq643dzvmxxqkfbf5kznwj47tan9zt2curl \ -H "Authorization: Bearer oa_m9s346q3d25vt4f5v37e3s3e28jt97kb6cq643dzvmxxqkfbf5kznwj47tan9zt2" \ https://api.openalarm.io/v1/alarm/k7m3x9q2f8d4w1b5n6p0r3t7v2x5z9c4/triggerEvery endpoint is a plain GET and requests are bodyless - the URL is the whole call. The key
gates the request; the ID in the path names which alarm or panic button it acts on. (POST is
reserved for future endpoints that accept a request body.)
Send the key as a header only. OpenAlarm never accepts an API key in the URL as a query
parameter, and the alarm ID is not a secret - it identifies an alarm, it does not authorize
anything. That is what makes a GET endpoint safe: a URL on its own cannot fire an alarm.
What Comes Back
Section titled “What Comes Back”| Status | Meaning |
|---|---|
202 |
Accepted. Every successful call returns this. |
401 |
Unauthorized - your API key is missing or invalid. |
404 |
Alarm ID not found / Panic ID not found. |
There is one success code. Arming, disarming, and triggering all return 202 Accepted - the call
has been accepted and will be applied. For a trigger, alerts go out after the false alarm delay, so nothing has reached your contacts at the moment you get the response. You
never have to branch on which 2xx came back.
202 does not promise anyone was alerted. A trigger that folds into an open incident, lands in
test mode, or is cancelled inside the false alarm delay is accepted and recorded without reaching
anyone - see Arming, which walks the list if your webhook fires and nothing
happens.
The two failures never overlap. 401 always means the problem is your API key. 404 always
means your key is fine and the trigger named in the path is not one you can fire right now -
whether it does not exist, is not yours, is outside your key’s scope, or is disabled or deactivated
by your plan. Those are deliberately indistinguishable, so a narrowly-scoped key cannot be used to
work out which IDs are real. Nothing else is returned for authentication or lookup.
Repeat triggers are accepted, not rejected. You do not need to handle a separate case for an
alarm that is already triggered - if an incident is already open the trigger is recorded against it
and you still get 202. Several sensors triggering at once therefore never alert your contacts
twice.
The Response Body
Section titled “The Response Body”Every response the API produces uses the same four-field shape:
{ "error": false, "message": null, "traceId": "8f14e45f-ea0d-4a1b-9f2c-6b3d70c5e881", "data": { "environment": "live", "location": { "id": "2c9wvhrq52k5refhtvmmr0f8yjz5j9e9", "name": "Home" } }}error is the outcome. message is human-readable and null on success. data carries the
payload: the location the source belongs to, and environment, which tells you whether the call ran against your real contacts
(live) or as a test (test). Check it if your automation depends on being live; an alarm left
in test mode looks identical from the outside otherwise.
The one exception is 401, which is generated before your request reaches the API and returns
{"message":"Unauthorized"} on its own.
The Trace ID
Section titled “The Trace ID”traceId identifies that one call. It is not an alarm, account, or incident reference and grants no
access to anything.
Quote it when you report a problem. It resolves exactly what happened to a single request, which is otherwise hard to pin down after the fact - so logging it alongside your own automation’s records is worth doing.
See the API Reference for the full endpoint contract.