Skip to content
Noccela Developers Swagger UI SDK on GitHub Quickstart

Push API (webhooks)

The Noccela Push API sends HTTPS requests to your endpoint when tags enter or leave areas or change state. Set-up, validation, retries, event types, payloads.

The Push API, also called the event API, turns the direction around: instead of asking Noccela for data, you give Noccela an HTTPS endpoint and it calls you when something happens. It suits events that are infrequent but important, such as a forklift entering a zone or a tag going offline, where polling would add delay and a permanent WebSocket would be more than you need.

How it works

  1. Create an endpoint: tell Noccela the URL that will receive events.
  2. Register the endpoint: Noccela sends a challenge to the URL, and your server echoes it back.
  3. Subscribe the endpoint to the event types you want, with filters.
  4. Receive events as they happen, and acknowledge each request.
  5. Fetch missed events after downtime.

1. Create an endpoint

POST /eventapi/endpoint HTTP/1.1
Host: api.noccela.io
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "name": "Warehouse events",
  "url": "https://integration.example.com/noccela/events",
  "secret": "YOUR_ENDPOINT_SECRET",
  "retryPolicy": null
}

The response contains the new endpoint’s id. name and an absolute url are required.

Secret. If you set a secret, every event request carries the header Authorization: Basic followed by the Base64 encoding of noccela:YOUR_ENDPOINT_SECRET. Check it on every request. To change the secret later, use POST /eventapi/modifyendpoint.

Retry policy. Leave retryPolicy out or null to use the defaults:

Field Default Meaning
hoursToDiscard 6 Hours after the event when Noccela stops trying to deliver it
maxFailedAttempts 3 Failed attempts before the event is given up
cooldownBetweenAttempts 10 Minutes to wait between attempts
maxFailedTriesInSingleAttempt 100 Tries within one attempt
maxMinutesToWaitBetweenTriesInSingleAttempt 1 Longest wait between tries; the wait starts at 1 second and doubles up to this limit

A changed retry policy takes effect immediately. When modifying, send the full policy; to return to defaults, send the default values.

2. Register (validate) the endpoint

An endpoint must be validated before it can receive events. Call:

POST /eventapi/registerendpoint HTTP/1.1
Host: api.noccela.io
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{ "id": 123 }

Noccela then sends a challenge to your URL:

{ "type": "challenge", "challenge": "AAABBB" }

Your endpoint must answer 200 OK with the challenge string as the whole body, with no JSON around it (preferably as text/plain). When the challenge succeeds, the registration call returns 204 No Content and the endpoint is ready.

3. Subscribe to events

A subscription (also called a registration) links one endpoint to one event type, with optional parameters. It gets its own ID.

POST /eventapi/event HTTP/1.1
Host: api.noccela.io
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "endpointId": 123,
  "type": "AreaChange",
  "parameters": {
    "accountId": 1234,
    "siteId": 5,
    "deviceIds": null,
    "areaIds": [17, 18]
  }
}

Every event type accepts the common parameters accountId, siteId and deviceIds (null for every tag on the site). You can register the same type several times with different parameters, for example one subscription per group of tags; each must be removed separately. The OpenAPI description lists the event types as numbers (2 to 6); the examples here use their names.

4. Receive events

Each request to your endpoint has this shape:

Field Meaning
type Event type, for example AreaChange
ts Timestamp of the message (Unix time)
regId ID of the subscription that produced it
ev Array of one or more events of that type
ev[].id Event ID, increasing; use it to fetch missed events
ev[].ts When the event happened (Unix time)
ev[].p Event-specific payload

Example (illustrative values) of an AreaChange delivery:

{
  "type": "AreaChange",
  "ts": 1792656003120,
  "regId": 456,
  "ev": [
    {
      "id": 98231,
      "ts": 1792656001874,
      "p": {
        "deviceId": 1234567,
        "areaId": 17,
        "status": "inside",
        "secondsSinceChange": 340,
        "entrancePointId": 3
      }
    }
  ]
}

Acknowledge with 200 OK or 204 No Content. Anything else, including a timeout, counts as a failure: Noccela retries according to the retry policy and, if your system stays unreachable, a circuit breaker pauses deliveries for a while. Answer quickly and do the processing afterwards.

A minimal receiver in Node.js that handles the challenge, checks the secret and logs events:

// receiver.mjs: run behind HTTPS, for example a reverse proxy (Node.js 22 or later)
import { createServer } from 'node:http';
import { timingSafeEqual } from 'node:crypto';

const SECRET = process.env.NCC_PUSH_SECRET; // YOUR_ENDPOINT_SECRET
const expected = Buffer.from('Basic ' + Buffer.from(`noccela:${SECRET}`).toString('base64'));

function authorised(header = '') {
  if (!SECRET) return true;
  const given = Buffer.from(header);
  return given.length === expected.length && timingSafeEqual(given, expected);
}

createServer(async (req, res) => {
  if (req.method !== 'POST') return res.writeHead(405).end();
  let body = '';
  for await (const chunk of req) body += chunk;
  const message = JSON.parse(body);

  if (message.type === 'challenge') {
    return res.writeHead(200, { 'Content-Type': 'text/plain' }).end(message.challenge);
  }
  if (!authorised(req.headers.authorization)) return res.writeHead(401).end();

  res.writeHead(204).end(); // acknowledge first, then process
  for (const event of message.ev) {
    console.log(message.type, `subscription ${message.regId}`, `event ${event.id}`, event.p);
  }
}).listen(8080);

5. Fetch missed events

If your endpoint was down, fetch the stored events of a subscription. Pass the ID of the last event you processed to get only newer ones; leave it out to get all.

curl -s "https://api.noccela.io/eventapi/events?RegistrationId=456&EventId=98231" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

The response is { "events": [ … ] }, with each event in the same id, ts, p form as above.

Event types

AreaChange

A tag entered or left an area. One subscription can watch several areas.

Parameter Meaning
areaIds Areas to watch; leave out, null or empty for all areas of the site
Payload field Meaning
deviceId The tag
areaId The area
status inside (entered) or outside (left)
secondsSinceChange Seconds the tag spent inside or outside the area before this change
entrancePointId Closest entrance point of the area, if entrance points are configured in the layout

RoomChange

A tag entered or left one area, with tunable sensitivity. A tag counts as inside once it has stayed within the area’s boundary, plus a 0.5 m margin, long enough to meet both thresholds.

Parameter Default Meaning
areaId (required) The area to watch; area IDs come from the site layout
cooldownSeconds 60 After a tag leaves, how long before another entry can be reported; 0 disables
timeInAreaTreshold 5 Seconds the tag must spend inside or outside before the change counts; 0 disables
locationCountTreshold 5 Positions inside the area needed before the change counts; 0 disables

The parameter names are spelled Treshold in the API. The payload has deviceId, status (inside or outside) and, when the tag leaves, timeSpent in seconds; the message root also carries areaId. The event time is the moment the tag actually crossed, not the moment the thresholds were met.

TagStateChange

A tag’s state changed. The payload has deviceId and a state object with only the changed properties, such as name, fwVersion, floorId, signalLost, powerSave, areas, inCharger, groupId, secondaryTagGroupIds, batteryPercentage and cycleStride.

Parameter Meaning
properties Property names to report; leave out, null or empty for all

BeaconStateChange

A base station’s state changed. The payload has deviceId and a state object with the changed values: online, charging and voltage (mobile base stations), and radioDisabled.

Parameter Meaning
getDiagnostics Also report diagnostics: connectTimestamp, statusCode (error bitmask, 0 means all OK), pingTime in ms, clockMasterWanted and clockMasterActive

StrokeCount

A tag’s stroke counter increased. Stroke counting is an industrial feature that must be enabled for the tag. The payload has deviceId and strokeCount.

Parameter Default Meaning
updateFrequency 1 Send an event every time the count is a multiple of this number

Last updated 22 October 2026