Webhooks
Atlaas can POST an event to your HTTPS endpoint whenever something happens on your terminals.
Webhooks are on the Pro plan and above. Add and manage endpoints on the Webhooks page in the
portal; the signing secret (whsec_...) is shown there. You can send a test event and see the
recent deliveries for each endpoint from the same page.
Events
An endpoint with no event filter receives every event below.
| Event | When it fires |
|---|---|
instance.state | A terminal changed state (deploying, running, stopped, error). |
order.place | An order was submitted to the broker. |
order.modify | An open order or position was modified. |
order.close | A position was closed. |
order.cancel | A pending order was cancelled. |
ea.connected | The connector EA attached to a terminal. |
ea.disconnected | The connector EA dropped off a terminal. |
deployment.completed | An expert advisor finished deploying. |
deployment.failed | An expert advisor failed to deploy. |
Request
Each delivery is a POST with a JSON body:
{
"id": "cm1delivery0000example",
"type": "order.place",
"createdAt": "2026-10-01T09:30:00.000Z",
"data": {
"accountId": "cm1account0000example",
"instanceId": "cm1instance000example",
"level": "INFO",
"message": "Order placed: BUY 0.10 EURUSD @ 1.0850 (ticket 123456)"
}
}
data always carries accountId, instanceId (or null), level (INFO, WARN, ERROR, ...) and message. Event-specific
fields are added alongside them, and fields are only ever added, never renamed.
Headers:
| Header | Value |
|---|---|
X-Atlas-Event | The event type, e.g. order.place. |
X-Atlas-Delivery | The delivery id, the same as id in the body. Use it to dedupe retries. |
X-Atlas-Signature | t=<unix seconds>,v1=<hex>, see below. |
Verifying the signature
v1 is the hex HMAC-SHA256 of `${t}.${rawBody}` keyed with your endpoint's secret. Sign the
raw request body exactly as received, before any JSON parsing, and reject old timestamps to
stop replays.
import { createHmac, timingSafeEqual } from "node:crypto"
function verifyAtlasWebhook(secret, rawBody, header, toleranceSeconds = 300) {
const t = /(?:^|,)t=(\d+)(?:,|$)/.exec(header)?.[1]
const v1 = /(?:^|,)v1=([0-9a-f]+)(?:,|$)/.exec(header)?.[1]
if (!t || !v1) return false
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false
const expected = Buffer.from(createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"), "hex")
const given = Buffer.from(v1, "hex")
return expected.length === given.length && timingSafeEqual(expected, given)
}
Delivery and retries
- Respond with any
2xxwithin 8 seconds to acknowledge the delivery. - A timeout, network error,
5xx,408or429is retried up to 3 attempts in total, after 1 s and 5 s. - Any other
4xxis treated as a deliberate rejection and is not retried. - Redirects are never followed. Register the final URL.
- An endpoint that fails 20 deliveries in a row is disabled. Re-enable it from the portal.
- Retries happen in memory, so an Atlaas restart during the backoff can drop the remaining attempts. Reconcile through the API if you need every event.