Skip to main content
Subscribe to account lifecycle events via the Webhooks endpoints and react in your backend the moment something happens — no polling.

Event types

Subscribe with an explicit list or "*" for everything.
High-volume events (fill.created, account.balance_changed) are never delivered through a * subscription — an endpoint must list them explicitly. This protects existing wildcard endpoints from suddenly receiving a firehose of per-fill events.
Events carry contextual blocks where relevant: trigger (what caused it, for example rule_violation, profit_target, first_trade), ruleType (which rule fired, for example max_loss, daily_loss), payout (payout ID, amounts, balances), import (import key details), and previousAttributes for change events.

Payload format

Every delivery is a JSON object with the same envelope: For account.* events, data is the full account object as of the event: identifiers (id, accountNumber, customerId), type, status, balances (initialBalance, currentBalance, highWaterMark, dailyStartingBalance), timestamps, violationReason, metadata, plus nested context where available: trader (email, name, externalUserId), tradingPlan, tradingRule, and the active lockout.

Example: account.status_changed

Example: account.payout_processed

Payout events add a payout block with the withdrawal details. data is the account after the payout — data.currentBalance equals payout.balance_after.
payout.mll_locked_to is set when the payout was executed with moveMllToLock; consistency_reset mirrors that request option. When a payout hits the rule’s maxPayouts, a separate account.max_payouts_reached event fires alongside it carrying the same payout.payout_id and payout.payout_count.

Example: fill.created

Fill events are fill-centric: the fill is top-level and the account is nested context. account.currentBalance is the account balance recorded at the moment the fill was booked — including this fill’s realized P&L, fees, and commission — and is identical on the webhook delivery, the live event stream frame and any ?since= replay of the same event.
fill.created is one event per order once it is fully filled — filledQuantity is the order’s total and filledPrice the weighted average. Deduplicate on orderId: a repeated orderId is always a redelivery, never a second fill of the same order.

account.balance_changed

One event every time an account’s balance changes, whatever moved it. If you mirror balances on your side this is the only event you need to follow.
The values are captured at the moment the balance moved and are identical on the webhook delivery, the live WebSocket frame and the ?since= replay; the id is the same on every channel, so deduplicate on it. Like fill.created, webhook deliveries are only recorded while an endpoint explicitly lists the event; the WebSocket stream carries it regardless.
Apply account.balance_changed as it arrives and reconcile periodically against GET /v1/organization/balances — one row per account with the authoritative currentBalance, up to 500 accounts per page, and ?updatedSince= to fetch only the accounts that moved since your last check.
You can send yourself a sample of any event type with the webhook test endpoint: POST /v1/organization/webhooks/{webhookId}/test with { "eventType": "account.payout_processed", "accountId": "<account id>" } builds the payload from a real account (read-only) and delivers it to your endpoint as webhook.test.

Verifying signatures

Every delivery is HMAC-SHA256 signed with your endpoint’s secret (whsec_..., shown when you create the webhook). Request headers: The signed message is `${timestamp}.${rawBody}`:
Compute the HMAC over the raw request body, before any JSON parsing — re-serialized JSON may not match byte-for-byte.

Delivery, retries, and auto-disable

  • Your endpoint should respond 2xx within 10 seconds; anything else counts as a failed attempt.
  • Failed deliveries retry up to 5 attempts with backoff: immediately, then after 1 min, 5 min, 30 min, and 2 h.
  • Consecutive failures eventually auto-disable the endpoint (you can re-enable it from the dashboard or API once your endpoint is healthy).
  • Any event can be redelivered on demand from the dashboard or API — which is also why you should deduplicate.

Deduplication

Store X-Hyperprop-Delivery IDs you’ve processed and skip repeats. Retries and manual redeliveries reuse the same event payload, so an idempotent consumer is all you need for exactly-once effects.