Flowyer
Connecting external AI assistants
How to connect ChatGPT, Claude, Gemini, Grok, DeepSeek or Cursor to Flowyer, and what an API key can and cannot do.
What is this?
With a personal API key an external AI assistant can read and create records (matters, clients, tasks, time entries, costs and documents) in Flowyer on your behalf and, where you allow it, modify them. Every request runs with exactly your permissions, narrowed further by what you allow on the key; matters, clients and tasks a bot created carry a small marker in the lists showing which key created them, and for time entries, costs and documents the creating key is recorded but shown only to an office administrator, under "Records created through the API".
What a key can NOT do
- It can never delete anything (a DELETE request always answers 405).
- It can change a record only through the PATCH operations and fields offered, passing the record's expected_updated_at (409 on a conflict); nothing else is overwritten.
- It can download a document's contents only with the separate download permission (documents:download), through the short-lived signed link of documents.download; it has no other access to the files.
- It never sees more than you do: case walls and module permissions apply unchanged.
Creating an API key
- An office administrator enables API access for the office under Settings > API keys (it is off by default).
- On the same page you create a key: give it a name (e.g. "ChatGPT") so you know later which bot each key identifies.
- Tick what the bot may do (read, create or modify) and set an expiry. A key's permissions cannot be changed later: if more is needed, create a new key.
- The key is shown only once: copy it into the assistant's settings. You can revoke it any time, with immediate effect.
Give every bot its own key. They can be revoked separately, and the matter, client and task lists show which one created a record.
Available permissions
matters:readRead mattersmatters:createCreate mattersmatters:updateUpdate mattersclients:readRead clientsclients:createCreate clientsclients:updateUpdate clientstasks:readRead taskstasks:createCreate taskstasks:updateUpdate tasksworkhours:readRead time entriesworkhours:createRecord time entriesworkhours:updateUpdate time entriescosts:readRead costscosts:createRecord costscosts:updateUpdate costsinvoices:readRead invoicesdocuments:readList documents (metadata only, no download)documents:downloadDownload documents (full contents)documents:createUpload documentsdocuments:updateRename documentscolleagues:readList colleagues (names only)knowledge:readRead knowledge baseknowledge:createCreate knowledge base entriesknowledge:updateUpdate knowledge base entriesemails:readRead case emailslitigation:readList litigation historylitigation:createCreate litigation history entrieslitigation:updateUpdate litigation history entriesmail_register:readRead mail registermail_register:createCreate mail register entriesmail_register:updateUpdate mail register entriescomments:readRead case commentscomments:createPost case commentscomments:updateEdit own case commentstrials:readRead hearingstrials:createCreate hearingstrials:updateUpdate hearingscourts:readList courtshr:readRead who is on leave (dates only)calendar:readRead calendar eventscalendar:createCreate calendar eventscalendar:updateUpdate calendar eventsbookings:readView appointment bookingsbookings:createCreate appointment bookings (emails the client)bookings:updateReschedule and edit bookingsbookings:sendConfirm or cancel bookings (emails the client)tickets:readRead support ticketstickets:replyReply to tickets (emails the client)tickets:updateChange ticket statusportal:readClient portal: read threads and messagesportal:replyClient portal: reply to the client (posts a message and emails them)
Connecting
Always use the exact https host starting with www. (a redirect would drop the authorization header). For API-key connections, send the key as "Authorization: Bearer <key>"; MCP clients instead authenticate with OAuth, signing in through the browser, so no key needs to be entered.
- Base URL
https://www.flowyer.com/api/agent- OpenAPI
https://www.flowyer.com/api/agent/openapi.json- MCP
-
https://mcp.flowyer.com/mcp
ChatGPT (Actions)
In a custom GPT, import the OpenAPI description below under Actions, choose API key authentication with the "Bearer" type and paste your Flowyer key.
https://www.flowyer.com/api/agent/openapi.json
Grok
Give Grok the address of the OpenAPI description and the key; the description tells it which operations exist and which parameters they take.
Claude Code
Claude Code connects to the MCP server; on first use it signs you in through the browser (OAuth), no key needed:
claude mcp add --transport http flowyer https://mcp.flowyer.com/mcp
Claude Desktop / Cursor / Gemini CLI / DeepSeek
Claude Desktop, Cursor, the Gemini CLI and DeepSeek-based MCP clients take the same MCP address in their configuration file; on first connection the client signs you in through the browser (OAuth), no key needs to be entered:
{
"mcpServers": {
"flowyer": {
"url": "https://mcp.flowyer.com/mcp"
}
}
}
REST (curl)
Direct REST call examples:
curl -H "Authorization: Bearer flw_..." https://www.flowyer.com/api/agent/me
curl -H "Authorization: Bearer flw_..." "https://www.flowyer.com/api/agent/matters?q=2026/0025"
curl -X POST -H "Authorization: Bearer flw_..." -H "Content-Type: application/json" \
-H "Idempotency-Key: 7f3a9c21-1b2c-4d5e-8f90-0a1b2c3d4e5f" \
-d '{"name":"Kovács Kft.","email":"info@kovacs.hu"}' https://www.flowyer.com/api/agent/clients
Rules
Safe retries (Idempotency-Key)
Every create accepts an Idempotency-Key header (or an idempotency_key field): a request repeated with the same value returns the same record instead of creating another, and different keys always create different records. Without a key, an identical create within 120 seconds returns the first record.
Errors
Every error has the same shape: a machine code (error), an English message (message) and the message in the office language (message_localized). The message says what to do next. Retrying an unchanged request makes no sense on 401, 403, 404 and 422, with two exceptions: on 404 upload_not_finished, finish the upload to upload_url first, then call complete again; on an expired OAuth access token (401 expired_key), refresh the token first.
{
"error": "scope_missing",
"message": "This API key does not have the \"clients:create\" permission. ...",
"message_localized": "Ehhez az API-kulcshoz nem tartozik \"clients:create\" jogosultság. ...",
"locale": "hu",
"details": { "required_scope": "clients:create" }
}
| HTTP | error | Meaning |
|---|---|---|
| 400 | invalid_json, use_www_host, bad_request | Malformed request: invalid JSON body, wrong host (use the www. host) or an unreadable request. |
| 401 | missing_key, invalid_key, revoked_key, expired_key, user_inactive, office_not_found | The key is missing, invalid, revoked or expired, its owner is no longer active, or the office of the key cannot be found. |
| 403 | scope_missing, module_forbidden, forbidden, office_api_disabled, licence_expired, office_archived | A permission is missing on the key or the user, or the office has not enabled the API. |
| 404 | not_found, matter_not_visible, unknown_endpoint, upload_not_finished, replay_not_visible | The record does not exist or the user may not see it; unknown endpoint; the uploaded file has not reached storage yet (upload_not_finished: upload it to upload_url, then call complete again); or a retried create whose record was created earlier but has since been deleted or hidden (replay_not_visible: nothing new was created, do not create it again). |
| 405 | delete_not_allowed, update_not_allowed, method_not_allowed | Deleting is not possible through the API; modifying only where the description offers a PATCH operation. |
| 409 | client_exists, client_exists_generic, idempotency_key_reused, duplicate_in_progress, record_conflict, record_locked, duplicate_name | A client with that name already exists; a document with that name already exists in the folder (duplicate_name); the record changed since you read it (record_conflict: read it again and resend the change with the new updated_at); the record has been invoiced or locked (record_locked: make the change in Flowyer); the Idempotency-Key was used on another resource; or an identical request is being processed. |
| 413 | request_too_large, file_too_large | The request body is too large (request_too_large), or the file to upload exceeds the limit (file_too_large; details.max gives the limit in bytes). |
| 422 | validation_failed, unknown_client, unknown_colleague, blocked_file_type, upload_token_invalid, folder_not_in_matter, document_name_too_long | An invalid or missing field (details.fields shows which); an invalid, used or expired upload token (upload_token_invalid: start the upload again); or a folder that does not belong to the matter (folder_not_in_matter). |
| 429 | rate_limited, auth_rate_limited | Too many requests (300 per minute per key); the Retry-After header says when to retry. |
| 500 | server_error | Unexpected error. The request was logged under its request_id; retry later, and if it repeats, quote that id to Flowyer support. |
| 503 | office_maintenance, office_setup_incomplete, temporarily_unavailable | The office is temporarily unavailable (maintenance or setup in progress); the Retry-After header says when to retry. |
Privacy
The assistant's provider (e.g. OpenAI, Anthropic, xAI) sees every piece of data the key returns. Only give a key to a bot whose data processing the office has accepted, and only with the permissions it really needs.