Skip to content
AtlasDocs
Sign inGet started
Updated Oct 03, 2026

Webhooks

Push every auth event to your own server as signed JSON, with automatic retries and a delivery log. Discord channels are supported alongside.

Set one up

  1. 1

    Add a signed JSON webhook

    In Dashboard → Settings → API and webhooks, choose Add webhook, pick Signed JSON, paste an https:// URL and choose the events (empty means every event).

  2. 2

    Copy the secret

    A signing secret (whsec_…) is shown once. Store it on your server. New secret replaces it; the old one stops verifying at once.

  3. 3

    Send a test

    Test posts a ping event and records the result in the delivery log.

What you receive

One POST per event, Content-Type: application/json. The event name is the server's log type.

JSON
{
"id": "6f1c0b7e-9c3a-4d52-8d0e-5a2f4f6b9a10",
"event": "DENY",
"created_at": "2026-10-03T09:41:07.512Z",
"application_id": 77,
"data": {
"log_id": 48213,
"type": "DENY",
"message": "HWID mismatch - lock violation.",
"license_key": "ATLAS-7F2C-91B8-E04D",
"hwid": "9F3A61C27D08",
"ip": "203.0.113.24",
"timestamp": "2026-10-03T09:41:07.498Z"
}
}
Events
SUCCESS
A sign-in was accepted.
DENY
A sign-in was refused. message carries the server's reason.
BAN
An alert rule banned a license, machine or address.
DISCONNECT
A session ended.
WARN
Something worth a look that was not refused.
ERROR
The server hit an error.
ADMIN
An admin action on a session or license.
LOG
A message your client sent with SubmitLog.
ping
The Test button.
Headers
X-Atlas-Event
The event name.
X-Atlas-Delivery
A delivery id, the same on every retry. Store it to ignore duplicates.
X-Atlas-Timestamp
Unix seconds when the attempt was made.
X-Atlas-Signature
v1= then the hex HMAC-SHA256 of timestamp + "." + body, keyed with your secret.

Verify the signature

const crypto = require('crypto');
// rawBody must be the request body exactly as received, before any JSON parsing.
function verify(rawBody, headers, secret) {
const ts = headers['x-atlas-timestamp'];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // reject replays
const want = 'v1=' + crypto.createHmac('sha256', secret).update(ts + '.' + rawBody).digest('hex');
const got = headers['x-atlas-signature'] || '';
return got.length === want.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want));
}

Retries and limits

  • Answer with any 2xx within 6 seconds. Anything else, or no answer, is retried after 30 seconds, 2 minutes, 10 minutes, 1 hour and 6 hours, then marked failed. Redirects are not followed.
  • The log keeps the last 14 days per webhook, with the status code, time taken and attempt count. Send again re-queues a delivery.
  • A webhook that fails 20 deliveries in a row is switched off and shows why. Turning it back on resets the count.
  • https only, public addresses only. Atlas checks the address again when it connects, so a name that points at a private network is refused.