Chat API
Overview
How to authenticate against the Chat API, what a token acts as, the rate limits and the error format.
The Chat API lets a script, a calendar or another system act as a person in Chat: set their status, post a message in a channel, and send contracts for signature. It lives on its own host, without a /chat prefix on the paths.
Base URL: https://chat.polder.work/api/v1
Note The incoming webhooks and mail endpoints are different: they live under
/api/webhooks,/api/workflowsand/api/mailand authenticate with a secret in the URL, not with an API key.
Create a token
Tokens are personal. Every member creates their own:
- Open Chat and go to Settings > API tokens (
/app/settings/api-tokensonchat.polder.work). - Give the token a name (up to 60 characters).
- Optionally tie it to one workspace.
- Tick the scopes it needs. Leave all unticked for a token that only needs the status and message endpoints.
- Copy the token. It starts with
mcp_.
You can have 10 active tokens at the same time. Revoke a token from the same screen; it stops working immediately, and the screen shows when it was last used.
The same token also works for the Chat MCP server (/mcp/chat). The name mcp_ is a leftover of that.
Send it as a bearer token:
curl https://chat.polder.work/api/v1/status \
-H "Authorization: Bearer $POLDER_TOKEN" \
-H "Accept: application/json"
Send Accept: application/json so validation errors come back as JSON.
What a token acts as
A token acts as the member who created it, nothing more and nothing less. Messages you post carry your name, are not marked as coming from a script, and you can edit or delete them in Chat. Every call goes through the same permission checks as the Chat screens, so a token never sees a channel or contract its member could not see.
A token stops working when:
- it is revoked,
- the member's account is suspended or loses access to Chat,
- it is tied to a workspace and the member is no longer in that workspace.
All of these return the same 401.
Workspace-bound tokens
A token without a workspace speaks for its member in every workspace they belong to. That is enough for status and channels and messages.
A token tied to one workspace only works inside that workspace. The contract endpoints require this: contracts are sent under a workspace's name, so they refuse a token that is not tied to one (403).
Scopes
Scopes can only narrow a token; they never give a member extra rights.
| Scope | Opens |
|---|---|
contracts |
The contract endpoints. A token created without it gets 403. |
Tokens created before scopes existed carry none, and cannot reach the contract endpoints. Create a new token for that.
AI access
The channel and message endpoints only reach workspaces that have the AI access feature switched on (off by default). In a workspace where it is off, its channels are missing from the channel list and posting into them returns 404.
Rate limits
| Limit | Applies to |
|---|---|
| 60 requests per minute per token | All /api/v1 endpoints |
| 10 requests per minute per token | POST /api/v1/contracts, on top of the limit above |
Requests without a valid token are counted per IP address. Over the limit you get 429 with a Retry-After header.
Errors
| Status | Meaning |
|---|---|
401 |
Missing, unknown or revoked token, or the token's member can no longer use Chat. Body: {"error": "…"}. |
403 |
The token lacks a required scope ({"error": "…"}), or may not do this (message endpoint), or is not tied to a workspace (contracts). |
404 |
Not found, or not visible to this token. Deliberately the same answer for "does not exist" and "not yours". |
409 |
Contract document not available yet. |
422 |
Validation failed, or the channel is archived. |
429 |
Rate limit exceeded. |
Validation errors use the standard Laravel shape:
{
"message": "The body field is required.",
"errors": { "body": ["The body field is required."] }
}
Errors raised by the endpoints themselves (403, 404, 409, and 422 for an archived channel) have a message in the language of the request, set by the Accept-Language header (nl or en).
Endpoints
| Page | Endpoints |
|---|---|
| Status | GET, PATCH /api/v1/status |
| Channels and messages | GET /api/v1/channels, POST /api/v1/messages |
| Contracts | templates, send, list, read, download |
| Incoming webhooks and mail | POST /api/webhooks/{token}, /api/workflows/{token}, /api/mail/inbound/{token} |