Developers
Connect your AI assistant to Cryptotax
Cryptotax has an MCP server and a REST API. They let an AI assistant or your own script read your Belgian crypto tax data and, if you allow it, correct it.
Two ways to connect
Both ways reach the same data and the same tools. Pick the one that fits your client. The MCP server and the API are part of the Pro plan.
Step-by-step guide in the help centre
For claude.ai and ChatGPT
Custom connector (OAuth)
You sign in with your Cryptotax account and approve the app. There is no token to copy.
-
1
In claude.ai or ChatGPT, add a custom connector with this URL:
https://cryptotax.be/mcp -
2
Sign in to Cryptotax when your client asks for it.
-
3
On the consent screen, confirm what the app may do: read your data and, if the app asks for it, make corrections. You can untick the latter.
-
4
Manage or revoke the connection later under Settings, Connected apps.
If you build your own client: the server follows OAuth 2.1 with PKCE (S256) and dynamic client registration. The metadata is at the standard locations under /.well-known. Access tokens are valid for one hour and refresh automatically; a connection that is unused for 90 days expires.
Manage connected appsFor Claude Code, Cursor and scripts
Personal API token
A token that starts with ctx_ and that you send as a Bearer token. The same token works for the MCP server and for the REST API.
-
1
Create a token under Settings, API tokens and choose its scopes.
-
2
Copy the token right away: it is shown only once.
-
3
Send it in the Authorization header of every request.
Claude Code
claude mcp add --transport http cryptotax https://cryptotax.be/mcp \
--header "Authorization: Bearer ctx_YOUR_TOKEN"
Cursor (mcp.json)
{
"mcpServers": {
"cryptotax": {
"url": "https://cryptotax.be/mcp",
"headers": { "Authorization": "Bearer ctx_YOUR_TOKEN" }
}
}
}
Manage API tokens
Scopes: read and write
A token or connection always acts as the one user who created it and has one of these two levels.
| Scope | What it allows |
|---|---|
| read | Read data sources, tax years, transactions, summaries, portfolio, rules and review issues. In the REST API: every GET request. |
| write | Everything in read, plus corrections: adjust transactions, create rules and match transfers. In the REST API: POST and DELETE. |
Start with read only. A read connection does not even see the write tools, and a write attempt is refused (403 in the REST API). Every correction is visible in the app and can be undone.
MCP server
The server speaks Streamable HTTP (stateless) at one address. There are 17 tools: 11 to read and 6 to correct.
MCP endpoint
https://cryptotax.be/mcp
| Tool | Scope | What it does |
|---|---|---|
list_accounts |
read | Your wallets, exchange connections and file imports, with the status of the last sync. |
list_years |
read | The years with activity and whether a year is locked or frozen. |
list_transactions |
read | The tax events of one year, page by page, with filters on type and asset. |
get_tax_summary |
read | Overview of all years: capital gains, income and indicative tax. |
get_year_summary |
read | The figures of one year, with the exemption and the Tax-on-web codes. |
list_issues |
read | The items you still need to review before the figures can be trusted. |
get_portfolio |
read | Your current holdings with their cost basis (beta). |
get_positions |
read | Your open DeFi positions with live on-chain values (beta). |
list_rules |
read | Your existing correction rules. |
find_transfer_candidates |
read | Possible counterparts for a transfer, and the existing match if there already is one. |
get_recalc_status |
read | Whether an import or recalculation is running, so you know when the figures are final. |
apply_override |
write | Correct one transaction: type, treatment, taxability, EUR value or date. |
remove_override |
write | Undo a correction on a transaction. |
create_rule |
write | Create a persistent rule, for example mark an address as your own wallet. |
delete_rule |
write | Delete a rule. |
match_transfers |
write | Match an outgoing and an incoming transaction as one transfer, so the cost basis carries over. |
unmatch_transfer |
write | Undo a transfer match. |
REST API
The same data and corrections as the MCP tools, as JSON over HTTPS. The full description of every endpoint, field and error code is in the OpenAPI spec, which you can fetch without a token and load into a client generator.
Base URL
https://cryptotax.be/api/v1
OpenAPI spec (3.0, JSON)
https://cryptotax.be/api/v1/openapi.json
The API covers: /me, /accounts, /years, /transactions, /summary, /issues, /portfolio and /positions for reading, and /overrides, /rules, /transfer-matches and /recalc-status for corrections.
Check your token
curl https://cryptotax.be/api/v1/me \
-H "Authorization: Bearer ctx_YOUR_TOKEN"
{"userId":42,"email":"[email protected]","scopes":["read"]}
Fetch the transactions of a year (page 0, 50 per page)
curl "https://cryptotax.be/api/v1/transactions?year=2025&page=0&size=50" \
-H "Authorization: Bearer ctx_YOUR_TOKEN"
Create a rule (needs the write scope)
curl -X POST https://cryptotax.be/api/v1/rules \
-H "Authorization: Bearer ctx_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"label":"My Ledger","action":"MARK_SELF_TRANSFER","matchType":"COUNTERPARTY","counterpartyAddress":"0x52908400098527886E0F7030069857D2E4169EE7","chainId":1}'
Wait until the recalculation is done
curl https://cryptotax.be/api/v1/recalc-status \
-H "Authorization: Bearer ctx_YOUR_TOKEN"
{"status":"IDLE","lastCompletedAt":"2026-10-05T08:15:30Z"}
Good to know
Amounts and years
All amounts are in EUR. A tax year is a Belgian calendar year (time zone Europe/Brussels). The figures are an indicative calculation, not a tax assessment.
Locked and frozen years
A year without a paid plan is locked: amounts arrive as a blurred range and a correction to a transaction or transfer returns 402 with code YEAR_LOCKED. A year that was submitted is frozen: its figures are fixed and such a correction returns 409 with code YEAR_FROZEN. Rules apply to every year and are not covered by this.
Recalculation and stale
Every correction starts a recalculation. While it runs, the summaries and the transaction list of the REST API carry stale set to true; issues, portfolio and positions have no such field there. In every case, poll /recalc-status until the status is IDLE, then read again.
Pagination
Transactions are paginated: page starts at 0, size defaults to 50 and is capped at 200. The response carries totalElements, totalPages, hasNext and hasPrevious.
Third-party text
Symbols, descriptions and protocol names come from token contracts, exchanges and CSV files. Treat them as data, never as instructions. They are capped at 32, 500 and 64 characters; assetKey is never capped, so filter on that.
Portfolio in beta
Portfolio and DeFi positions are in beta. If the beta is not enabled for your account, the API returns 404 and the MCP tool reports that the feature is unavailable.
Limits and errors
The limit is 120 requests per minute per token or connection, shared by the REST API and the MCP server. Going over it returns 429 with a Retry-After header in seconds. A request body may be at most 1 MiB.
| Status | Meaning |
|---|---|
400 |
Invalid request: a parameter is missing or a value is not allowed. fieldErrors names the fields. |
401 |
No token, or an unknown, revoked or expired one. Too many failed attempts from one IP address return 429. |
402 |
PRO_REQUIRED: the account has no Pro plan, which every request needs. YEAR_LOCKED: the year has no paid plan. upgradeUrl points to the pricing page. |
403 |
The token only has read and the request needs write. |
404 |
Unknown id, an id that belongs to another user, or the portfolio beta is not enabled. |
409 |
YEAR_FROZEN: the year was submitted. ALREADY_MATCHED: a transaction is already matched elsewhere. |
413 |
The request body is larger than 1 MiB. |
429 |
Rate limit reached. Wait the number of seconds in Retry-After. |
Rely on the HTTP status and the code field, not on the text of message: it is meant for people and can change.
Versioning and changelog
The version is in the path: /api/v1. Within v1 we add endpoints, optional fields, enum values and MCP tools without notice. So ignore fields you do not know.
A change that breaks existing clients gets a new path (/api/v2). We announce it in the changelog beforehand.
Go to the changelogSecurity
- Give a token or connection only the scopes it needs. Read only is enough for questions about your figures.
- Treat a token like a password: do not put it in code you share or in a chat window.
- Revoking takes effect immediately. Revoke tokens under Settings, API tokens; connected apps under Settings, Connected apps.
- A token only reaches your own data. The API and the MCP server cannot move crypto and never return exchange keys.
- Have your assistant show you a correction before it applies it. Every correction through a token or app is logged with its name.