Webhooks
Register an endpoint, choose event types, and MFX Hub posts each event to it as signed JSON, exactly as the events channel carries it. Deliveries are retried with backoff; an endpoint can be paused and resumed; every event that did not arrive is in a log you can read and replay.
POST /v1/webhooks
Idempotency-Key: hook-0001
{"url": "https://example.com/mfx", "event_types": ["position.opened", "position.closed", "terminal.*"]}
event_types takes an event’s type (position.closed), a family (terminal.*) or *. Ticks and candles are never sent this way. The endpoint’s signing secret is in this answer and in no other; rotate it with POST /v1/webhooks/{id}/rotate-secret.
Verifying a delivery
Each delivery carries these headers:
| Header | What |
|---|---|
MFX-Signature |
t=<unix seconds>,v1=<hex>: HMAC-SHA256, keyed with the endpoint’s secret, over <t>.<body>. For a day after a rotation there are two v1 values, the new secret’s first |
MFX-Event-Id |
The event’s id. Delivery is at least once: de-duplicate on it |
MFX-Event-Type |
The event’s type |
MFX-Delivery-Attempt |
1 for the first try |
Verify the signature over the body exactly as received, before you parse it, and refuse a t more than five minutes from your clock. The Python SDK does both in one call: mfx.webhooks.verify(body, header, secret).
When a delivery fails
A delivery that does not answer 2xx is tried again after 10 seconds, 1 minute, 5 minutes, 30 minutes and 2 hours. After the last attempt it is a dead letter, kept with its payload so you can read it and ask for it again. An endpoint that has delivered nothing for 24 hours while events failed is paused, and a webhook.endpoint_paused event says so on the stream; you resume it.