Automation & API Available
MCP (Model Context Protocol)
Point an AI client at your own instance and ask in plain language. Nothing gets exported and no second data path appears: the MCP server talks in-process to the same API the web app uses.
What you need
- Your own tenant hostname over HTTPS: the verified custom domain, or <slug>.<base domain>
- A licence covering the mcp sku; without it the whole /mcp mount answers 402
- SCHAKL_MCP_ENABLED must not be false (it is on by default)
- The apikeys.personal.manage permission for a personal key, or apikeys.service_account.manage for a service account
- A client that speaks Streamable HTTP, for example Claude Code or Claude Desktop
How to connect it
- 1 Check your licence under Instellingen → Licentie (Settings → Licence). MCP has its own sku (
mcp); if it is not covered,/mcpanswers 402 and there is nothing to connect to. - 2 Mint a personal key under Instellingen → Mijn account (Settings → My account), section API-sleutels (API keys). Fill in Naam (Name), leave Verloopt op (Expires on) empty for a key that never expires, and under Scopes tick exactly the permissions the AI may exercise. Press Sleutel aanmaken (Create key).
- 3 Or mint a key that needs nobody's account: Instellingen → Service-accounts → Service-account toevoegen (Add service account), then Nieuwe sleutel (New key) with its own scopes.
- 4 Copy the key straight away. It has the form
schakl_<prefix>_<secret>and is shown exactly once; afterwards the API only ever returnsschakl_<prefix>_********. - 5 Connect Claude Code:
claude mcp add --transport http schakl https://<your-host>/mcp --header "Authorization: Bearer schakl_…" - 6 Any other Streamable-HTTP client: endpoint
https://<your-host>/mcp, headerAuthorization: Bearer schakl_…orX-API-Key: schakl_…. Always use your own tenant hostname; a key presented on another organisation's hostname is simply not found. - 7 Done with the client, or lost the key: press Intrekken (Revoke) beside it, or delete the whole service account. Anything still using it loses access immediately.
The same gate as the web app
There is no second data path. A tool call goes in-process through the same handling as an HTTP request: the hostname resolves the organisation, row-level security is bound, and the key's permissions are resolved. A call that is not allowed surfaces the API's own 401 or 403 envelope as a tool error. The incoming key is never forwarded to any external service; the proxy only ever calls the API in-process.
Read-first is a choice at mint time
The tool surface includes writes, because the whole API is in it. What a client may actually do lives in the key's scopes: tick read permissions only and there is nothing to change. A personal key is additionally capped by its owner's live permissions on every request, so demoting someone narrows their keys with them. A service-account key carries exactly the scopes you granted it.
- Scopes come from the same permission catalogue as roles, including the own/any variant such as time.entry.read:own
- The API's deny-by-default rule answers every call, an AI's included
- Only enabled modules contribute routes, so the tool surface tracks what you actually run
Transport and pace
Streamable HTTP, stateless, with JSON responses: every JSON-RPC POST stands alone, so it works behind any load balancer and from plain curl. Each key is limited to 600 requests per minute, generous for automation and a firm ceiling under a leaked key. The Laatst gebruikt (Last used) column deliberately lags: it is updated out of band, so a tool call never waits on it.
Permissions
Grant these to the role that manages this integration (Settings → Roles). Admin-only by default, and never to the client role.
-
apikeys.personal.manageManage your own API keys: mint and revoke them yourself. Granted to admin and member by default, because such a key can never exceed its owner. -
apikeys.service_account.manageManage service accounts: shared principals that belong to no one person. Admin only by default.
What it deliberately does not do
- No OAuth 2.1: the resource-server layer (RFC 9728) has not been built. A client that requires the full OAuth flow cannot connect today; an API key is the only credential.
- Not everything is a tool: /api/v1/auth, /api/v1/setup, /api/v1/instance, /api/v1/users and the import upload endpoints (/inspect and /import) are deliberately excluded. The column list and the export side of import and export stay reachable.
- The hand-written per-module tools (companies.find, projects.budget_status) feed the in-app assistant today; the MCP tool surface is derived purely from the OpenAPI spec.
- The older SSE transport is not offered, it is deprecated.
- 600 requests per minute per key is a fixed ceiling, not a setting.
- SCHAKL_MCP_ENABLED=false removes the whole /mcp surface; there is no per-tool switch.
Where to find it Instellingen → Mijn account (Settings → My account), section API-sleutels, for a personal key, or Instellingen → Service-accounts (Settings → Service accounts) for a key that outlives an employee. The endpoint itself is https://<your-host>/mcp.
Read the guide