Events

Webhooks

The platform POSTs a JSON event to your HTTPS endpoint whenever something happens to a client, account, trade or transaction. Every delivery is signed; failed deliveries are retried for a day.

#Set up

In the Octolit CRM: Settings › API & Webhooks › Webhooks › New endpoint. Enter your HTTPS URL, tick the events and optional extra data. Each endpoint has its own signing secret (whsec_ + 40 characters, shown once). Rotate secret creates a new one; both are valid for 24 hours and deliveries carry two v1= signatures meanwhile. Send test event posts webhook.test.

Trade, margin and demo events need the brand switch Trading webhooks. The delivery log in the CRM shows every attempt with status, duration and your response body; failed events can be re-sent by hand.

#Delivery

Request headers
POST /hooks/octolit HTTP/1.1
Host: your-backend.example
Content-Type: application/json
User-Agent: TradingCRM-Webhooks/1
X-Webhook-Id: evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1
X-Webhook-Event: trade.opened
X-Webhook-Timestamp: 1762853400
X-Webhook-Signature: t=1762853400,v1=5f1c0b8e9d3a…
X-Webhook-IdThe event id (evt_…), the same for every retry - use it for idempotency.
X-Webhook-EventThe event type, same as type in the body.
X-Webhook-TimestampUnix seconds when this attempt was sent.
X-Webhook-Signaturet=<unix seconds>,v1=<hex> where v1 = HMAC-SHA256(secret, "<t>.<raw body>"). A second ,v1=… appears during secret rotation.
Your answerAny 2xx within 10 seconds counts as delivered. The body is ignored (but logged, 1 KB). Redirects are not followed.

#Verify the signature

  1. Take the raw request body bytes (never re-serialised JSON).
  2. Read t from the signature header; reject if it is more than 300 seconds from now.
  3. Compute HMAC-SHA256 over t + "." + body with your endpoint secret, hex-encoded lowercase.
  4. Compare in constant time with each v1 value; one match is enough.
  5. Answer 200 fast; do the work on a queue; ignore an event id you have already processed.
Receiving endpoint
import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';

const app = express();
app.post('/hooks/octolit', express.raw({ type: 'application/json' }), (req, res) => {
  const raw = req.body.toString('utf8');                  // the raw bytes, not re-serialised JSON
  const sig = req.get('X-Webhook-Signature') || '';
  const t = /t=(\d+)/.exec(sig)?.[1];
  const macs = [...sig.matchAll(/v1=([0-9a-f]+)/g)].map((m) => m[1]);
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.status(400).end();
  const expected = createHmac('sha256', process.env.OCTOLIT_WEBHOOK_SECRET).update(`${t}.${raw}`).digest('hex');
  const ok = macs.some((m) => m.length === expected.length && timingSafeEqual(Buffer.from(m), Buffer.from(expected)));
  if (!ok) return res.status(401).end();
  const event = JSON.parse(raw);
  if (seen(event.id)) return res.status(200).end();        // delivered twice: ignore
  queue(event);                                           // do the work later
  res.status(200).end();                                  // answer within 10 s
});

Paste a real delivery into the webhook verifier to check your implementation.

#Retries

A non-2xx answer, a timeout or a connection error schedules the next attempt. Each delay gets 0-10 % jitter.

AttemptAfter the previous one
11 minute
25 minutes
330 minutes
41 hour
52 hours
66 hours
714 hours
8final (about 24 h after the first try)
Consequences
After the last attempt the event is marked failed in the delivery log and can be re-sent by hand. An endpoint that keeps failing is paused; the CRM shows it. Events may arrive more than once and out of order - key your processing on id and compare created_at before overwriting state.

#The envelope

Every event
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "client.updated",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "…": "…"
  }
}
id string required

evt_... - the same on every retry and resend.

type string required
created_at string<date-time> required
company_id integer required
data object required

#Events

17 event types. Click one in the sidebar or scroll. Each shows the data object and a complete example.

EVENTclient.created

#A client was created

data

client Client optional

The CRM's client. email / phone are masked unless the key carries clients:read_email / clients:read_phone.

Child fields (24)
id integer optional
first_name string | null optional
last_name string | null optional
full_name string | null optional
email string | null optional
emails string[] optional
phone string | null optional
phones string[] optional
brand object | null optional
Child fields (2)
id integer optional
name string optional
desk object | null optional
Child fields (2)
id integer optional
name string optional
sales_status string | null optional
sales_status_changed_at string<date-time> | null optional
kyc object optional
Child fields (2)
id_status string | null optional
billing_status string | null optional
active boolean optional
is_lead boolean optional
deleted boolean optional
country string | null optional
external_user_id string | null optional

Your client id.

agents object[] optional
Item fields (2)
id integer optional
name string optional
created_at string<date-time> optional
updated_at string<date-time> optional
first_deposit_date string<date-time> | null optional

Only with clients:read_ftd.

comments any[] optional

Only with clients:read_comments.

custom_fields object optional

Only with clients:read_custom_fields.

changed_fields string[] | null optional

client.updated only.

previous_agents any[] optional

client.agent_changed only.

POST · client.created
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "client.created",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "first_name": "Ana",
      "last_name": "Ortiz",
      "full_name": "Ana Ortiz",
      "email": "ana.ortiz@example.com",
      "emails": [
        "ana.ortiz@example.com"
      ],
      "phone": "+357 99 123456",
      "phones": [
        "+357 99 123456"
      ],
      "brand": {
        "id": 1042,
        "name": "Main"
      },
      "desk": {
        "id": 1042,
        "name": "Main"
      },
      "sales_status": "string",
      "sales_status_changed_at": "2026-11-11T09:30:00Z",
      "kyc": {
        "id_status": "string",
        "billing_status": "string"
      },
      "active": true,
      "is_lead": true,
      "deleted": true,
      "country": "CY",
      "external_user_id": "abc123",
      "agents": [
        {
          "id": 1042,
          "name": "Main"
        }
      ],
      "created_at": "2026-11-11T09:30:00.000000Z",
      "updated_at": "2026-11-11T09:31:12.000000Z",
      "first_deposit_date": "2026-11-11T09:30:00Z",
      "comments": [
        null
      ],
      "custom_fields": {}
    },
    "changed_fields": [
      "string"
    ],
    "previous_agents": [
      null
    ]
  }
}
EVENTclient.updated

#A client's tracked fields changed (`data.changed_fields`)

data

client Client optional

The CRM's client. email / phone are masked unless the key carries clients:read_email / clients:read_phone.

Child fields (24)
id integer optional
first_name string | null optional
last_name string | null optional
full_name string | null optional
email string | null optional
emails string[] optional
phone string | null optional
phones string[] optional
brand object | null optional
Child fields (2)
id integer optional
name string optional
desk object | null optional
Child fields (2)
id integer optional
name string optional
sales_status string | null optional
sales_status_changed_at string<date-time> | null optional
kyc object optional
Child fields (2)
id_status string | null optional
billing_status string | null optional
active boolean optional
is_lead boolean optional
deleted boolean optional
country string | null optional
external_user_id string | null optional

Your client id.

agents object[] optional
Item fields (2)
id integer optional
name string optional
created_at string<date-time> optional
updated_at string<date-time> optional
first_deposit_date string<date-time> | null optional

Only with clients:read_ftd.

comments any[] optional

Only with clients:read_comments.

custom_fields object optional

Only with clients:read_custom_fields.

changed_fields string[] | null optional

client.updated only.

previous_agents any[] optional

client.agent_changed only.

POST · client.updated
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "client.updated",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "first_name": "Ana",
      "last_name": "Ortiz",
      "full_name": "Ana Ortiz",
      "email": "ana.ortiz@example.com",
      "emails": [
        "ana.ortiz@example.com"
      ],
      "phone": "+357 99 123456",
      "phones": [
        "+357 99 123456"
      ],
      "brand": {
        "id": 1042,
        "name": "Main"
      },
      "desk": {
        "id": 1042,
        "name": "Main"
      },
      "sales_status": "string",
      "sales_status_changed_at": "2026-11-11T09:30:00Z",
      "kyc": {
        "id_status": "string",
        "billing_status": "string"
      },
      "active": true,
      "is_lead": true,
      "deleted": true,
      "country": "CY",
      "external_user_id": "abc123",
      "agents": [
        {
          "id": 1042,
          "name": "Main"
        }
      ],
      "created_at": "2026-11-11T09:30:00.000000Z",
      "updated_at": "2026-11-11T09:31:12.000000Z",
      "first_deposit_date": "2026-11-11T09:30:00Z",
      "comments": [
        null
      ],
      "custom_fields": {}
    },
    "changed_fields": [
      "string"
    ],
    "previous_agents": [
      null
    ]
  }
}
EVENTclient.agent_changed

#The assigned agents changed (`data.previous_agents`)

data

client Client optional

The CRM's client. email / phone are masked unless the key carries clients:read_email / clients:read_phone.

Child fields (24)
id integer optional
first_name string | null optional
last_name string | null optional
full_name string | null optional
email string | null optional
emails string[] optional
phone string | null optional
phones string[] optional
brand object | null optional
Child fields (2)
id integer optional
name string optional
desk object | null optional
Child fields (2)
id integer optional
name string optional
sales_status string | null optional
sales_status_changed_at string<date-time> | null optional
kyc object optional
Child fields (2)
id_status string | null optional
billing_status string | null optional
active boolean optional
is_lead boolean optional
deleted boolean optional
country string | null optional
external_user_id string | null optional

Your client id.

agents object[] optional
Item fields (2)
id integer optional
name string optional
created_at string<date-time> optional
updated_at string<date-time> optional
first_deposit_date string<date-time> | null optional

Only with clients:read_ftd.

comments any[] optional

Only with clients:read_comments.

custom_fields object optional

Only with clients:read_custom_fields.

changed_fields string[] | null optional

client.updated only.

previous_agents any[] optional

client.agent_changed only.

POST · client.agent_changed
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "client.agent_changed",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "first_name": "Ana",
      "last_name": "Ortiz",
      "full_name": "Ana Ortiz",
      "email": "ana.ortiz@example.com",
      "emails": [
        "ana.ortiz@example.com"
      ],
      "phone": "+357 99 123456",
      "phones": [
        "+357 99 123456"
      ],
      "brand": {
        "id": 1042,
        "name": "Main"
      },
      "desk": {
        "id": 1042,
        "name": "Main"
      },
      "sales_status": "string",
      "sales_status_changed_at": "2026-11-11T09:30:00Z",
      "kyc": {
        "id_status": "string",
        "billing_status": "string"
      },
      "active": true,
      "is_lead": true,
      "deleted": true,
      "country": "CY",
      "external_user_id": "abc123",
      "agents": [
        {
          "id": 1042,
          "name": "Main"
        }
      ],
      "created_at": "2026-11-11T09:30:00.000000Z",
      "updated_at": "2026-11-11T09:31:12.000000Z",
      "first_deposit_date": "2026-11-11T09:30:00Z",
      "comments": [
        null
      ],
      "custom_fields": {}
    },
    "changed_fields": [
      "string"
    ],
    "previous_agents": [
      null
    ]
  }
}
EVENTclient.deleted

#A client was deleted (`data.client` = id + deleted_at only)

data

client Client optional

The CRM's client. email / phone are masked unless the key carries clients:read_email / clients:read_phone.

Child fields (24)
id integer optional
first_name string | null optional
last_name string | null optional
full_name string | null optional
email string | null optional
emails string[] optional
phone string | null optional
phones string[] optional
brand object | null optional
Child fields (2)
id integer optional
name string optional
desk object | null optional
Child fields (2)
id integer optional
name string optional
sales_status string | null optional
sales_status_changed_at string<date-time> | null optional
kyc object optional
Child fields (2)
id_status string | null optional
billing_status string | null optional
active boolean optional
is_lead boolean optional
deleted boolean optional
country string | null optional
external_user_id string | null optional

Your client id.

agents object[] optional
Item fields (2)
id integer optional
name string optional
created_at string<date-time> optional
updated_at string<date-time> optional
first_deposit_date string<date-time> | null optional

Only with clients:read_ftd.

comments any[] optional

Only with clients:read_comments.

custom_fields object optional

Only with clients:read_custom_fields.

changed_fields string[] | null optional

client.updated only.

previous_agents any[] optional

client.agent_changed only.

POST · client.deleted
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "client.deleted",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "first_name": "Ana",
      "last_name": "Ortiz",
      "full_name": "Ana Ortiz",
      "email": "ana.ortiz@example.com",
      "emails": [
        "ana.ortiz@example.com"
      ],
      "phone": "+357 99 123456",
      "phones": [
        "+357 99 123456"
      ],
      "brand": {
        "id": 1042,
        "name": "Main"
      },
      "desk": {
        "id": 1042,
        "name": "Main"
      },
      "sales_status": "string",
      "sales_status_changed_at": "2026-11-11T09:30:00Z",
      "kyc": {
        "id_status": "string",
        "billing_status": "string"
      },
      "active": true,
      "is_lead": true,
      "deleted": true,
      "country": "CY",
      "external_user_id": "abc123",
      "agents": [
        {
          "id": 1042,
          "name": "Main"
        }
      ],
      "created_at": "2026-11-11T09:30:00.000000Z",
      "updated_at": "2026-11-11T09:31:12.000000Z",
      "first_deposit_date": "2026-11-11T09:30:00Z",
      "comments": [
        null
      ],
      "custom_fields": {}
    },
    "changed_fields": [
      "string"
    ],
    "previous_agents": [
      null
    ]
  }
}
EVENTclient.login

#A client signed in (password, link or single sign-on)

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
login object optional
Child fields (6)
method enum optional

password, a mailed sign-in link, your SSO token / the partner API, or a CRM agent signing in as the client.

passwordlinkssoagent
two_factor boolean optional

The second sign-in step (code) was passed.

app enum | null optional
traderdashboardnull
ip string | null optional
device string | null optional

Browser / system from the user agent, e.g. "Chrome / Windows".

at string<date-time> optional
POST · client.login
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "client.login",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "login": {
      "method": "password",
      "two_factor": false,
      "app": "trader",
      "ip": "203.0.113.42",
      "device": "iPhone",
      "at": "2026-11-11T09:30:00.000000Z"
    }
  }
}
EVENTclient.inactive

#A client has not signed in for N days (the brand's "inactive after" setting)

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
last_login_at string<date-time> | null optional
inactive_days integer optional
POST · client.inactive
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "client.inactive",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "last_login_at": "2026-10-01T12:00:00Z",
    "inactive_days": 30
  }
}
EVENTaccount.created

#A trading account was opened

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
account TradingAccount optional
Child fields (15)
id integer optional
name string optional
currency string optional
demo boolean optional
type object | null optional
Child fields (3)
id integer optional
name string optional
provider string optional

internal or mt.

balance string | number | null optional
equity string | number | null optional
margin string | number | null optional
free_margin string | number | null optional
margin_level string | number | null optional
open_pl string | number | null optional
closed_pl string | number | null optional
credit string | number | null optional
mt_login string | null optional

MT accounts only.

created_at string<date-time> | null optional
created_by string | null optional

client

POST · account.created
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "account.created",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "account": {
      "id": 1042,
      "name": "Main",
      "currency": "USD",
      "demo": false,
      "type": {
        "id": 1042,
        "name": "Main",
        "provider": "string"
      },
      "balance": "10250.00",
      "equity": "10312.40",
      "margin": "108.45",
      "free_margin": "10203.95",
      "margin_level": "9509.3",
      "open_pl": "string",
      "closed_pl": "string",
      "credit": "string",
      "mt_login": "string",
      "created_at": "2026-11-11T09:30:00.000000Z"
    },
    "created_by": "string"
  }
}
EVENTtrade.opened

#A position was opened

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
position Position optional
Child fields (22)
id integer optional
account_id integer | null optional
symbol string optional
status enum optional
openpendingclosed
side enum optional
buysell
order_type integer | null optional
amount string | number | null optional

Margin used (account currency).

trade_amount string | number | null optional

Position value (account currency).

units number | null optional
lot_size number | null optional
leverage number | null optional
open_price string | number | null optional
stop_loss string | number | null optional
take_profit string | number | null optional
profit string | number | null optional
commission string | number | null optional
swap string | number | null optional
market string | null optional
opened_at string<date-time> | null optional
closed_at string<date-time> | null optional
closed_by string | null optional
created_at string<date-time> | null optional
changed_fields string[] optional

trade.modified only.

POST · trade.opened
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "trade.opened",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "position": {
      "id": 1042,
      "account_id": 55,
      "symbol": "EURUSD",
      "status": "open",
      "side": "buy",
      "order_type": 1,
      "amount": "100.00",
      "trade_amount": "string",
      "units": 10000,
      "lot_size": 1.5,
      "leverage": 100,
      "open_price": "string",
      "stop_loss": "string",
      "take_profit": "string",
      "profit": "19.00",
      "commission": "0.00",
      "swap": "-0.12",
      "market": "string",
      "opened_at": "2026-11-11T09:30:00Z",
      "closed_at": "2026-11-11T10:05:12Z",
      "closed_by": "string",
      "created_at": "2026-11-11T09:30:00.000000Z"
    },
    "changed_fields": [
      "string"
    ]
  }
}
EVENTtrade.modified

#A position's stop loss / take profit / amount changed

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
position Position optional
Child fields (22)
id integer optional
account_id integer | null optional
symbol string optional
status enum optional
openpendingclosed
side enum optional
buysell
order_type integer | null optional
amount string | number | null optional

Margin used (account currency).

trade_amount string | number | null optional

Position value (account currency).

units number | null optional
lot_size number | null optional
leverage number | null optional
open_price string | number | null optional
stop_loss string | number | null optional
take_profit string | number | null optional
profit string | number | null optional
commission string | number | null optional
swap string | number | null optional
market string | null optional
opened_at string<date-time> | null optional
closed_at string<date-time> | null optional
closed_by string | null optional
created_at string<date-time> | null optional
changed_fields string[] optional

trade.modified only.

POST · trade.modified
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "trade.modified",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "position": {
      "id": 1042,
      "account_id": 55,
      "symbol": "EURUSD",
      "status": "open",
      "side": "buy",
      "order_type": 1,
      "amount": "100.00",
      "trade_amount": "string",
      "units": 10000,
      "lot_size": 1.5,
      "leverage": 100,
      "open_price": "string",
      "stop_loss": "string",
      "take_profit": "string",
      "profit": "19.00",
      "commission": "0.00",
      "swap": "-0.12",
      "market": "string",
      "opened_at": "2026-11-11T09:30:00Z",
      "closed_at": "2026-11-11T10:05:12Z",
      "closed_by": "string",
      "created_at": "2026-11-11T09:30:00.000000Z"
    },
    "changed_fields": [
      "string"
    ]
  }
}
EVENTtrade.closed

#A position was closed (`data.position.closed_by` = user, tp, sl, stop_out, admin, ...)

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
position Position optional
Child fields (22)
id integer optional
account_id integer | null optional
symbol string optional
status enum optional
openpendingclosed
side enum optional
buysell
order_type integer | null optional
amount string | number | null optional

Margin used (account currency).

trade_amount string | number | null optional

Position value (account currency).

units number | null optional
lot_size number | null optional
leverage number | null optional
open_price string | number | null optional
stop_loss string | number | null optional
take_profit string | number | null optional
profit string | number | null optional
commission string | number | null optional
swap string | number | null optional
market string | null optional
opened_at string<date-time> | null optional
closed_at string<date-time> | null optional
closed_by string | null optional
created_at string<date-time> | null optional
changed_fields string[] optional

trade.modified only.

POST · trade.closed
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "trade.closed",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "position": {
      "id": 1042,
      "account_id": 55,
      "symbol": "EURUSD",
      "status": "open",
      "side": "buy",
      "order_type": 1,
      "amount": "100.00",
      "trade_amount": "string",
      "units": 10000,
      "lot_size": 1.5,
      "leverage": 100,
      "open_price": "string",
      "stop_loss": "string",
      "take_profit": "string",
      "profit": "19.00",
      "commission": "0.00",
      "swap": "-0.12",
      "market": "string",
      "opened_at": "2026-11-11T09:30:00Z",
      "closed_at": "2026-11-11T10:05:12Z",
      "closed_by": "string",
      "created_at": "2026-11-11T09:30:00.000000Z"
    },
    "changed_fields": [
      "string"
    ]
  }
}
EVENTdemo.first_trade

#The client's first trade on a demo account

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
position Position optional
Child fields (22)
id integer optional
account_id integer | null optional
symbol string optional
status enum optional
openpendingclosed
side enum optional
buysell
order_type integer | null optional
amount string | number | null optional

Margin used (account currency).

trade_amount string | number | null optional

Position value (account currency).

units number | null optional
lot_size number | null optional
leverage number | null optional
open_price string | number | null optional
stop_loss string | number | null optional
take_profit string | number | null optional
profit string | number | null optional
commission string | number | null optional
swap string | number | null optional
market string | null optional
opened_at string<date-time> | null optional
closed_at string<date-time> | null optional
closed_by string | null optional
created_at string<date-time> | null optional
changed_fields string[] optional

trade.modified only.

POST · demo.first_trade
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "demo.first_trade",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "position": {
      "id": 1042,
      "account_id": 55,
      "symbol": "EURUSD",
      "status": "open",
      "side": "buy",
      "order_type": 1,
      "amount": "100.00",
      "trade_amount": "string",
      "units": 10000,
      "lot_size": 1.5,
      "leverage": 100,
      "open_price": "string",
      "stop_loss": "string",
      "take_profit": "string",
      "profit": "19.00",
      "commission": "0.00",
      "swap": "-0.12",
      "market": "string",
      "opened_at": "2026-11-11T09:30:00Z",
      "closed_at": "2026-11-11T10:05:12Z",
      "closed_by": "string",
      "created_at": "2026-11-11T09:30:00.000000Z"
    },
    "changed_fields": [
      "string"
    ]
  }
}
EVENTmargin.call

#The client's margin level fell to the brand's margin call level

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
account_id integer | null optional
margin_level string | number | null optional

The account's margin level in percent when the event was raised.

level integer | null optional

The brand's margin call level in percent (CRM Settings > API & Webhooks > Broker login, default 100). margin.call is sent once when the account goes under it and again every hour while it stays under; stop.out when positions were closed by the margin rule.

equity string | number | null optional
margin string | number | null optional
closed_positions integer[] optional

stop.out only.

POST · margin.call
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "margin.call",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "account_id": 55,
    "margin_level": "9509.3",
    "level": 100,
    "equity": "10312.40",
    "margin": "108.45",
    "closed_positions": [
      1
    ]
  }
}
EVENTstop.out

#Positions were closed by the stop-out rule

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
account_id integer | null optional
margin_level string | number | null optional

The account's margin level in percent when the event was raised.

level integer | null optional

The brand's margin call level in percent (CRM Settings > API & Webhooks > Broker login, default 100). margin.call is sent once when the account goes under it and again every hour while it stays under; stop.out when positions were closed by the margin rule.

equity string | number | null optional
margin string | number | null optional
closed_positions integer[] optional

stop.out only.

POST · stop.out
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "stop.out",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "account_id": 55,
    "margin_level": "9509.3",
    "level": 100,
    "equity": "10312.40",
    "margin": "108.45",
    "closed_positions": [
      1
    ]
  }
}
EVENTprice_alert.triggered

#A client's price alert fired (the level was crossed)

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
alert object optional
Child fields (9)
id integer optional
account_id integer | null optional

The trading account the alert's price type belongs to.

symbol string optional

The pair as the trader shows it (EUR/USD).

price_kind enum optional
bidask
direction enum optional

The side of the level the alert waited for.

abovebelow
price string | number optional

The alert level.

triggered_price string | number | null optional

The price that crossed it.

triggered_at string<date-time> optional
note string | null optional

The client's own note on the alert.

POST · price_alert.triggered
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "price_alert.triggered",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "alert": {
      "id": 1042,
      "account_id": 55,
      "symbol": "EURUSD",
      "price_kind": "bid",
      "direction": "above",
      "price": "string",
      "triggered_price": "string",
      "triggered_at": "2026-11-11T09:30:00Z",
      "note": "Card deposit"
    }
  }
}
EVENTdeposit.status

#A deposit changed status (pending, approved, declined, cancelled)

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
transaction object optional
Child fields (9)
id integer optional
kind enum optional
depositwithdrawal
status enum optional
pendingapproveddeclinedcancelledrefunded
previous_status string | null optional
amount string | number optional
currency string optional
account_id integer | null optional
method string | null optional
at string<date-time> optional
POST · deposit.status
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "deposit.status",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "transaction": {
      "id": 1042,
      "kind": "deposit",
      "status": "pending",
      "previous_status": "pending",
      "amount": "100.00",
      "currency": "USD",
      "account_id": 55,
      "method": "card",
      "at": "2026-11-11T09:30:00.000000Z"
    }
  }
}
EVENTwithdrawal.status

#A withdrawal changed status (pending, approved, declined, cancelled)

data

client ClientRef optional
Child fields (3)
id integer optional
external_id string | null optional

Your client id (external_user_id).

brand object | null optional
Child fields (2)
id integer optional
name string optional
transaction object optional
Child fields (9)
id integer optional
kind enum optional
depositwithdrawal
status enum optional
pendingapproveddeclinedcancelledrefunded
previous_status string | null optional
amount string | number optional
currency string optional
account_id integer | null optional
method string | null optional
at string<date-time> optional
POST · withdrawal.status
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "withdrawal.status",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {
    "client": {
      "id": 1042,
      "external_id": "cust_10042",
      "brand": {
        "id": 1042,
        "name": "Main"
      }
    },
    "transaction": {
      "id": 1042,
      "kind": "deposit",
      "status": "pending",
      "previous_status": "pending",
      "amount": "100.00",
      "currency": "USD",
      "account_id": 55,
      "method": "card",
      "at": "2026-11-11T09:30:00.000000Z"
    }
  }
}
EVENTwebhook.test

#The "Send test event" button of the Octolit CRM

POST · webhook.test
{
  "id": "evt_01JCX7R0M6YQ3A8ZK5R4T2N9P1",
  "type": "webhook.test",
  "created_at": "2026-11-11T09:30:00.000000Z",
  "company_id": 10,
  "data": {}
}