LonexOne

Developers Webhooks

Webhooks

Get events pushed to your server, and check they really came from LonexOne.

Webhooks push events to your server as they happen, so you don't have to keep asking. They're the same events your Discord log channels can get, from new calls and warrants to promotions and staff actions, sent as JSON.

Setting one up

  1. In the LonexOne panel, open Developer API and choose Add a webhook.
  2. Enter an https:// address on your server, tick the events you want, and save.
  3. Copy the signing secret: it's shown once. You'll use it to check requests are really from LonexOne.
  4. Press Send a test. LonexOne sends a webhook.test event and tells you what your server answered.

A community can have up to five webhooks. Webhooks work whether or not you also post the events to Discord.

What you receive

Each event is a POST with a JSON body. data carries the same title, description and labelled fields as the Discord message, with Discord mentions written as @123….

POST to your address JSON
{
    "id": "0c2b6a1e-6f0a-4b8e-9c55-6a6c3f5d2e10",
    "event": "cad_call",
    "event_name": "New calls",
    "created_at": "2026-11-08T20:01:00+00:00",
    "community": {
        "id": 12,
        "name": "Sunnyside RP"
    },
    "data": {
        "department": null,
        "title": "Call #58: Shots fired",
        "description": null,
        "url": null,
        "fields": {
            "Priority": "1 Emergency",
            "Location": "Grove St",
            "Postal": "8012"
        }
    }
}
HeaderWhat it is
X-LonexOne-EventThe event, like cad_call. Same as event in the body.
X-LonexOne-DeliveryA unique id for this delivery. Retries keep the same id, so you can ignore repeats.
X-LonexOne-TimestampWhen it was sent, in Unix seconds.
X-LonexOne-Signaturesha256= and the HMAC-SHA256 of the timestamp, a dot, and the raw body, keyed with your signing secret.

Checking the signature

Work out the signature yourself from the raw body (before parsing it) and compare. Also refuse old timestamps, so a captured request can't be replayed later.

PHP PHP
$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_LONEXONE_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_LONEXONE_SIGNATURE'] ?? '';

$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, getenv('LONEXONE_WEBHOOK_SECRET'));

if (! hash_equals($expected, $signature) || abs(time() - (int) $timestamp) > 300) {
    http_response_code(401);
    exit;
}

$event = json_decode($body, true);
// $event['event'], $event['data']['title'], $event['data']['fields'] ...
http_response_code(204);
Node.js (Express) JavaScript
import crypto from 'node:crypto';
import express from 'express';

const app = express();

app.post('/lonexone-webhook', express.raw({ type: 'application/json' }), (req, res) => {
    const timestamp = req.get('X-LonexOne-Timestamp') ?? '';
    const signature = req.get('X-LonexOne-Signature') ?? '';
    const expected = 'sha256=' + crypto
        .createHmac('sha256', process.env.LONEXONE_WEBHOOK_SECRET)
        .update(`${timestamp}.${req.body}`)
        .digest('hex');

    const valid = signature.length === expected.length
        && crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
    if (!valid || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
        return res.sendStatus(401);
    }

    const event = JSON.parse(req.body);
    // event.event, event.data.title, event.data.fields ...
    res.sendStatus(204);
});

Responding and retries

  • Answer with any 2xx within 5 seconds. Do slow work after you've answered.
  • Anything else counts as a failure. LonexOne tries again after 10 seconds, 1 minute and 5 minutes.
  • After 25 failures in a row the webhook turns itself off, and the panel says why. Saving it again turns it back on.
  • Redirects aren't followed, and webhooks can't point at private or local addresses.

Events

The events you can pick depend on your community's modules.

Community

joinedJoined a department
leftLeft or removed
transferTransfers
promotionPromotions
demotionDemotions
disciplineDiscipline
certificationCertifications
leaveLeave
interestLetters of interest
applicationApplications
shiftShifts
courtsCourt cases

CAD

cad_callNew calls
cad_panicPanic buttons
cad_signalSignal 100
cad_arrestArrests filed
cad_warrantWarrants issued or requested
cad_warrant_approvedWarrants approved
cad_boloBOLOs
cad_report_submittedReports submitted
cad_report_returnedReports returned
cad_forced_offUnits signed off by a supervisor
cad_verdictCourt verdicts
cad_inspection_failedFailed fire inspections

Staff Panel

staff_banBans
staff_ban_pendingBans waiting for approval
staff_kickKicks
staff_serviceCommunity service
staff_warnWarnings
staff_commendCommendations
staff_revokedBans lifted and actions revoked
staff_reportNew reports and staff requests
staff_alertFlagged players and possible ban evasion joining
staff_appealNew appeals

Training

training_sessionTraining sessions
training_resultTraining results
training_requestRequests to join training