A trading report starts taking twice as long, but the API's average response time barely moves. That is possible if the delay sits in your queue, if only one expensive endpoint is affected, or if retries hide failures behind a successful final attempt. An HTTP uptime check cannot distinguish those situations.
MT5 API monitoring should explain whether the integration completes its intended work, where time is spent and what failed. This guide designs that evidence in the calling application. It does not describe an API service-level agreement, publish a MetaKit latency benchmark or assume access to private server telemetry. The examples use read-only requests and synthetic numbers.
Monitor an operation and its attempts separately
A user-visible report is a logical job. Fetching one page of positions is an HTTP attempt. A report can contain many attempts, and a single read may have several attempts after a retry. Give the job a private correlation identifier in your application logs, then count its requests separately.
Measure queue wait from enqueue to worker start, attempt duration around the request and body processing, and job duration from enqueue to completed output. Keep a count of expected and successfully reported accounts. A “successful” report that silently omits three disconnected accounts is a data-completeness failure even if every request it retained returned 200.
OpenTelemetry defines HTTP client request duration as a histogram in seconds. If you adopt its standard instrument names, follow those conventions and your instrumentation's precise timing boundary. The custom example below measures through JSON decoding and envelope validation, so it uses its own measurement name and milliseconds rather than claiming to be that standard instrument.
Keep failure categories useful
Distinguish a transport exception, a received HTTP failure, invalid JSON, an unexpected successful response shape and an incomplete logical job. These failures point to different investigations. Keep the raw HTTP status when available; an exception before a response should have a missing status rather than a fabricated zero or 500.
For MetaKit, read failures use the documented error envelope with error.code and error.message. Trading writes can additionally carry a rejected result and MT5 retcode. The current implementation distinguishes an HTTP 422 trading rejection from a 504 terminal_timeout. A timeout can leave execution outcome uncertain; it should never become an automatic “order failed, send a new one” action in a monitoring dashboard.
This is an operational classification problem, separate from choosing retries. Follow the idempotency guidance for execution uncertainty and the bounded client guide for read scheduling. An alert is evidence to investigate, not permission to place or duplicate a trade.
Instrument one read without leaking its contents
This original Node.js example calls the verified GET /v1/accounts/{id}/positions route. The token remains server-side, redirects are rejected and the telemetry record contains neither the account id nor the response body. Use a read-only credential obtained through the documented authentication flow.
async function readPositions(accountId, token, record,
fetcher = fetch, clock = () => performance.now()) {
if (!Number.isSafeInteger(accountId) || accountId < 1 ||
typeof token !== "string" || !token || typeof record !== "function") {
throw new Error("Invalid read configuration");
}
const started = clock();
let httpStatus = null, outcome = "transport_error";
try {
const response = await fetcher(
`https://api.metakit.cloud/v1/accounts/${accountId}/positions`,
{
method: "GET",
headers: { Authorization: `Bearer ${token}` },
redirect: "error",
signal: AbortSignal.timeout(8000),
}
);
httpStatus = response.status;
outcome = response.ok ? "decode_error" : "http_error";
const body = await response.json();
if (!response.ok) throw new Error(`Positions read: HTTP ${httpStatus}`);
outcome = "schema_error";
if (!body || !Array.isArray(body.data)) {
throw new Error("Unexpected positions envelope");
}
outcome = "ok";
return body;
} finally {
const durationMs = clock() - started;
try {
record({
route: "/v1/accounts/{id}/positions", method: "GET",
httpStatus, outcome, durationMs,
});
} catch {
// Telemetry failure must not replace the request result or exception.
}
}
}The Node performance API supplies the monotonic timing source used for this elapsed measurement. Wall-clock dates remain useful for correlating events, but clock corrections should not change an elapsed-duration calculation.
This small wrapper checks only the paginated envelope, not every position field, and returns one page. A complete report must validate the fields it uses and follow the documented pagination. A JSON error response is counted as an HTTP failure; malformed JSON on an unsuccessful response keeps that HTTP classification. Add richer parsing diagnostics separately if needed without copying the body into metrics.
Test with a successful response, a 403, a network exception, a timeout exception, invalid JSON, a malformed 200 envelope and a recorder that throws. Confirm exactly one observation per attempt and confirm the original result or exception survives telemetry failure. Mocks suffice for these tests; there is no reason to create a live trade.
Read distributions rather than a single average
Take twenty invented successful attempt durations: nineteen are 100 milliseconds and one is 2,100 milliseconds. The mean is 200 milliseconds. Under an explicitly chosen nearest-rank definition, p95 is 100 milliseconds, while p99 and the maximum are 2,100 milliseconds. The average hides the extreme; the small sample also makes the percentile coarse.
Always show the observation count and interval with a percentile. Compare like routes and similar work: one large history query and one small positions read are not interchangeable latency samples. Track error counts separately so excluding failed attempts from a “successful latency” chart remains visible.
The Prometheus histogram guide explains count/sum measurements, quantile estimation and aggregation. Do not average per-instance p95 values and call the result the fleet p95. Aggregate compatible histogram observations or buckets first, using the monitoring system's supported method. Bucket boundaries must be suitable for the latency range you need to inspect.
Diagnose a slow report in a fixed order
First check whether jobs started on time and reached a terminal state. Then inspect queue wait, per-route attempt durations, attempts per job and missing-account counts. Compare affected accounts through restricted logs rather than putting private account identifiers into globally searchable metric labels.
If queue wait rises while attempt times remain stable, inspect scheduling and worker occupancy. If attempt times and upstream errors rise together, increasing concurrency may amplify the problem. If only total job time rises, check pagination, retries, response size and work performed after requests return. These are diagnostic hypotheses, not proof of a server-side cause.
Finally, keep quote age separate from response time. A quick successful read can contain an old market observation. The quote freshness guide develops that independent clock and data-quality check. Likewise, a reachable account is not evidence that a report has collected every historical deal.
Choose alerts around the work you promise
For a daily report, an incomplete job by its deadline may be more useful than a single slow attempt. For an interactive panel, sustained slow responses and repeated missing accounts may matter sooner. Define thresholds from your own workload and user expectations; no threshold in this article is a MetaKit quota or availability commitment.
Use bounded labels such as route template, method, outcome category and status class. Avoid full URLs, bearer tokens, signing secrets, trade comments, raw payloads and unbounded exception messages. If account-level diagnosis is necessary, keep access-controlled logs with a retention policy appropriate to that information.
Start with one representative read and one complete report job, then verify that an intentionally failed synthetic attempt appears in the correct category. Check endpoint and pagination behavior against the MetaKit API documentation. A monitoring system is useful when its numbers lead to a reproducible investigation and make partial output visible.
Sources and verification
Verified 21 October 2026. Product response shapes and routes were checked against the current implementation. The wrapper was tested with mocks; the durations are invented arithmetic examples.
- OpenTelemetry HTTP metrics, standard measurement conventions.
- Node.js performance API, elapsed timing.
- Prometheus histograms and summaries, aggregation and quantiles.
- MetaKit API documentation, endpoint contracts.