The problem: two systems, one client
MT5 holds the trading truth: accounts, balances, positions and deals. The CRM holds the relationship: contact details, verification status, sales owner, notes and tasks. Staff need both views to agree. When they do not, sales calls the wrong clients, support gives outdated answers and finance spends time reconciling.
There are two common ways to keep them in sync: polling and webhooks.
Polling vs webhooks
With polling, the CRM asks MT5, or a service in front of it, for changes on a schedule. With webhooks, the integration service sends an HTTP request to the CRM each time something happens.
| Polling | Webhooks | |
|---|---|---|
| Freshness | As fresh as the polling interval | Near real time |
| Load | Repeated requests even when nothing changed | Requests only when something happens |
| Complexity | Simple to start, harder to scale | Needs a reliable receiver |
| Missed changes | Rare if the query is correct | Possible if retries run out |
| Best for | Reconciliation and backfill | Day-to-day sync and alerts |
In practice, most teams use both. Webhooks carry everyday changes. A scheduled reconciliation job, running far less often, catches anything missed.
Typical events to send
Start with events that change what staff do next. Names vary between providers. A typical set:
| Event | What it means | Typical CRM action |
|---|---|---|
| account.created | A new MT5 account was opened | Link the account to the contact |
| account.updated | Group, leverage or status changed | Update account fields |
| balance.deposit | A deposit was posted | Mark as funded, notify the sales owner |
| balance.withdrawal | A withdrawal was posted | Update totals, flag for retention review |
| deal.closed | A position was closed | Update activity and trading stats |
| margin.call | An account reached a margin call level | Create a task for support |
Avoid sending every tick or quote as a webhook. High-volume market data belongs in a stream designed for it, not in a CRM.
Payload design
A good webhook payload is small, stable and self-describing. Include:
- A unique event ID.
- The event type and a schema version.
- The time the event happened, in UTC.
- The IDs of the objects involved, such as MT5 login and client ID.
- The changed values the receiver needs, or enough IDs to fetch them.
Some teams send “thin” events with IDs only, and the receiver fetches the latest state through the API. That avoids acting on stale data when events arrive out of order.
Reliability: retries, idempotency and ordering
Retries
Networks fail and receivers restart. The sender should retry failed deliveries with increasing delays, and stop after a limit. The receiver should treat any non-2xx response as “try again” and any 2xx as “received”.
Acknowledge fast, process later
Return a 2xx as soon as the request is verified and stored. Do the real work in a background queue. Slow receivers cause timeouts, which cause retries, which cause duplicates.
Idempotency
Because of retries, the same event can arrive more than once. Store each event ID when you process it, and skip IDs you have already seen. For financial events, such as deposits, this check is essential.
Ordering
Do not assume events arrive in the order they happened. Use the event timestamp or a version number to ignore updates older than what you already have, or fetch current state before acting.
Security: signatures and secrets
- Accept webhooks only over HTTPS.
- Verify the signature on every request. A common pattern is an HMAC of the raw body with a shared secret, sent in a header.
- Check a timestamp in the signed data and reject old requests to limit replay.
- Store the secret in a secrets manager, not in code, and rotate it on a schedule.
- Do not trust payload content alone for money movements. Confirm against the source API when it matters.
Reconciliation as a safety net
Even with retries, an event can be lost: a long outage, a misconfigured endpoint or a bug. Run a reconciliation job on a schedule that compares key totals, such as account counts, balances and deposits per day, between MT5 and the CRM. Log differences and fix them through the same code path the webhooks use.
Testing in a sandbox
Never build a webhook receiver against production MT5. Use a sandbox and test accounts, and check each case on this list:
- Point the sandbox at a test endpoint and confirm delivery.
- Trigger each event type and check the CRM result.
- Send the same event twice and confirm it is processed once.
- Return errors from the receiver and confirm retries arrive.
- Send events out of order and confirm the CRM ends in the right state.
- Send a request with a bad signature and confirm it is rejected.
- Run the reconciliation job and confirm it finds no differences.
Monitoring in production
- Track delivery failures and retry counts.
- Alert when no events arrive for longer than usual.
- Track processing lag between event time and CRM update.
- Keep an audit log of events received and actions taken.
How XFIV Connect fits
XFIV Connect is an MT5 integration API with webhooks and a sandbox. It is designed for exactly this kind of sync between MT5 and broker systems such as CRMs and client portals. Requests are recorded in audit logs. See the XFIV Connect page and the developer docs.
Frequently asked questions
Can I use only webhooks, without polling?
You can, but a periodic reconciliation job is a good safety net. It catches events lost during long outages or configuration mistakes.
How do I stop a deposit from being recorded twice?
Store each event ID when you process it and skip any ID you have already seen. This is called idempotent processing.
How do I know a webhook really came from my provider?
Verify the signature on every request using the shared secret, and reject requests with old timestamps.
Should market data go through webhooks?
No. Webhooks suit discrete business events. Prices and ticks need a streaming interface built for volume.
