Conventions
These rules hold across every endpoint, without exception. They are worth two minutes now because they are the things that quietly corrupt a report six months later.
Numbers
5.96 means 5.96%, not 596% and not 0.0596.
Any field whose name ends in _percent follows this rule.15, not -15. It is a magnitude, and the field
name already says which direction it goes.currency is a separate field: never assume
USD, and never infer it from the broker.commission and swap keep their natural sign: a cost is negative, a credit is
positive. A swap you were paid is a positive number.null, never an omitted key and never 0. You should never have to
guess whether the value is zero or unknown.0 is a real value, so we never use it to mean "not set". A stop loss of 0 would be a
price. When there is no stop loss, the field is null.Which number is "the return"?
There are two, they answer different questions, and both are returned:
twr_percent does not.On the example account below they read 5.96 and 5.89. When they disagree sharply, the
account has had deposits or withdrawals: that is the whole difference between them.
Dates and times
Always ISO 8601 in UTC, with a trailing Z:
"opened_at": "2026-08-10T23:00:00Z"
Never a local time, never a broker's server time, never a Unix timestamp. Broker server time is a common source of off-by-a-few-hours bugs; converting to your own timezone is your call, and you have an unambiguous instant to do it from.
Identifiers
Objects are addressed by their slug: the same one in the public URL:
GET /api/v1/accounts/dark-algo
The internal composite id (mt4-26613005-…) is deliberately not part of this API. It encodes
the broker account number and the owner's user id, and we are not making that a permanent
part of a public contract.
Accounts and portfolios
A portfolio behaves exactly like an account: same endpoints, same shape, same statistics. They are distinguished by one field:
"type": "account" // or "portfolio"
Filter a listing with ?type=account or ?type=portfolio when you only want one kind.
Lists and pagination
Every endpoint that returns a list uses the same envelope:
{
"data": [ /* … */ ],
"pagination": {
"page": 1,
"limit": 50,
"total": 16,
"has_more": false
}
}
1.50, maximum 200.total: it stays
correct if items are added while you are paging.Attribution
Every account object carries an attribution field, and so does every list of trades or
positions, next to pagination:
"attribution": {
"required": true,
"text": "Data from ShowMyTrades",
"url": "https://showmytrades.com/account/dark-algo",
"account_url": "https://showmytrades.com/account/dark-algo"
}
It is the credit to show next to the data, already worded and already linked. On the free plan it is required, on Pro and Ultra it is recommended. The rules are in Attribution.
Rate limits
Limits are counted per key: 30 requests per minute on the free plan, 120 on Pro and Ultra. Requests without a key (public accounts only) are counted per IP address, 20 per minute. Every response carries your current standing:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1755864000
Over the limit you get a 429 with a Retry-After header in seconds.
Back off on that header rather than a fixed sleep.
Versioning
The version is in the path (/api/v1/). Within a version we will add fields but never
remove or repurpose one, and never change the meaning or the unit of an existing field.
Treat unknown fields as harmless: a parser that rejects them will break the first time we add something.
/api/v1/, are internal. They power
the website, they change shape whenever the interface changes, and they carry no guarantee
whatsoever. They are reachable, but building on them is building on sand.