# Workestra Agent Integration Documentation Canonical docs: https://docs.workestra.app/docs/api REST API: https://platform.workestra.app/api/v1 Hosted MCP API: https://platform.workestra.app/api/mcp Support: support@workestra.app Security: Never request or expose API keys in chat, URLs, screenshots, logs, or support messages. # API Reference Source: https://docs.workestra.app/docs/api Build and test integrations with the Workestra REST, MCP, and agent-trial APIs. Workestra exposes two authenticated developer surfaces: - **REST API** under `/api/v1` for resource-oriented integrations. - **Hosted MCP tool API** under `/api/mcp` for AI clients using the `workestra-mcp` STDIO adapter. The supported REST contract contains **7 paths and 17 HTTP operations**. The [Public API Status](/docs/api/status) page is the authoritative support boundary. > **Info:** **Giving this page to an AI assistant?** Ask it to read the [AI Agent Integration Guide](/docs/api/agent-guide) first. For broad AI automation, prefer MCP: it exposes live, permission-aware tool schemas. Do not probe unlisted REST routes or guess request fields. ## Canonical origin ```text https://platform.workestra.app ``` Use the platform origin directly. The apex and `www` origins are marketing surfaces, and API clients can discard an `Authorization` header when following a cross-host redirect. REST base URL: ```text https://platform.workestra.app/api/v1 ``` Hosted MCP endpoints: ```text GET /api/mcp/session GET|POST /api/mcp/tools/list POST /api/mcp/tools/call ``` ## Start here | Goal | Documentation | | --- | --- | | Hand this integration to an AI agent | [AI Agent Integration Guide](/docs/api/agent-guide) | | Choose MCP versus REST | [AI Agent Integration Guide](/docs/api/agent-guide#choose-the-integration-surface) | | Run REST smoke tests | [Testing guide](/docs/api/testing) | | Follow an end-to-end workflow | [Integration recipes](/docs/api/recipes) | | Diagnose an error or missing tool | [Troubleshooting](/docs/api/troubleshooting) | | See every supported REST path and method | [Public API Status](/docs/api/status) | | Create and scope an API key | [Authentication](/docs/api/authentication) | | Test MCP tools and retrieve their schemas | [MCP tool discovery](/docs/integrations/mcp/tools) | | Configure Codex, Claude, Cursor, or VS Code | [MCP Server](/docs/integrations/mcp) | | Verify outbound webhook signatures | [Webhooks](/docs/api/webhooks) | | Check OpenAPI publication status | [OpenAPI](/docs/api/openapi) | ## Authentication Use a Workestra API key in the bearer header: ```http Authorization: Bearer wks_your_api_key ``` API keys are workspace-scoped, revocable, may expire, and are shown only once. The `/api/v1` implementation also accepts an authenticated Workestra session JWT for first-party clients. Third-party integrations should use API keys. ## Response conventions Most v1 success responses use: ```json , "pagination": } ``` `pagination` is present only on paginated list responses. A small number of older handlers return their created object directly; check the endpoint guide or actual response before generating a strict client. Most v1 errors use: ```json } ``` Quota and MCP errors have older flat envelopes. Test clients should primarily branch on HTTP status and then read either `error.message` or a string `error`. ## Supported REST resources The public contract covers contacts, deals, projects, and issues/tasks. See the [endpoint guides](/docs/api/endpoints) for fields, examples, and edge cases. For other Workestra areas, use the live MCP tool catalog rather than probing application routes. The legacy Supabase Edge Function families `/api-contacts`, `/api-deals`, `/api-issues`, `/api-projects`, and `/api-ingest` are not the current REST contract. Do not use them for new integrations. ## Contract maturity OpenAPI publication is temporarily paused while the sanitized application artifact is released. Use the dedicated guides and runtime validation during today's tests. See [OpenAPI status](/docs/api/openapi). ## Contract levels | Level | Meaning | Agent behavior | | --- | --- | --- | | **Guide** | Fields and important behavior are documented | Safe to implement after reading the guide | | **Live MCP schema** | Deployed tool schema and permission result | Safe to call after retrieving the schema | | **Deprecated** | Compatibility route | Do not use for new work | | **Internal** | Not a public integration contract | Do not call | ## Agent handoff prompt A nontechnical user can give an assistant this URL and instruction: ```text Read https://docs.workestra.app/docs/api and its AI Agent Integration Guide. Prefer MCP for broad automation. Never ask me to paste an API key into chat. Retrieve live tool schemas before calls, explain writes before executing them, use disposable data for tests, and stop rather than guessing an unlisted REST contract. For unresolved integration errors, prepare a sanitized report for support@workestra.app. ``` ## Integration support Email [support@workestra.app](mailto:support@workestra.app). Include the workspace ID, UTC timestamp, method/path or MCP tool, status, request/delivery ID, client version, sanitized request/response, and reproduction steps. Never include API keys, tokens, private attachment URLs, or unnecessary personal data. # AI Agent Integration Guide Source: https://docs.workestra.app/docs/api/agent-guide The canonical handoff document for an AI assistant connecting to Workestra. This is the canonical starting point when a person asks an AI assistant to connect to Workestra. > **Warning:** Never ask the user to paste an API key into chat. Ask them to create a least-privilege key and save it through their AI client's secret, environment-variable, or MCP configuration interface. ## Canonical URLs | Purpose | URL | | --- | --- | | Documentation | `https://docs.workestra.app/docs/api` | | Agent guide | `https://docs.workestra.app/docs/api/agent-guide` | | REST API | `https://platform.workestra.app/api/v1` | | Hosted MCP API | `https://platform.workestra.app/api/mcp` | | OpenAPI status | `https://docs.workestra.app/docs/api/openapi` | | Short machine index | `https://docs.workestra.app/llms.txt` | | Complete agent bundle | `https://docs.workestra.app/llms-full.txt` | | Integration support | `support@workestra.app` | Use the `platform.workestra.app` origin directly. The apex and `www` origins are marketing surfaces, and some clients remove `Authorization` while following a cross-host redirect. ## Choose the integration surface | Need | Use | Why | | --- | --- | --- | | Let an AI assistant inspect and act on Workestra | MCP | Live tool schemas and permissions are discoverable per key | | Build a conventional service against a field-documented endpoint | REST | Stable resource-oriented HTTP contract | | Need an operation absent from the public status page | MCP or stop | An unlisted application route is not a supported external contract | | Receive events | Module webhook | Signed, asynchronous delivery | | Run a short human-approved evaluation | Agent trial | Guarded tool allowlist, expiry, and quota | > **Info:** For broad agent automation, MCP is the recommended surface. The REST status status page lists only the supported public REST contract. OpenAPI publication is temporarily paused; do not use a cached specification or probe unlisted application routes. ## MCP integration protocol Follow these steps in order: 1. Ask an Admin or Owner to open **Settings > AI > External Connections > API Keys**. 2. Create a separate temporary key for this integration. 3. Grant the smallest relevant preset or scope set and set an expiry for testing. 4. Configure `workestra-mcp` using the client's secret/configuration mechanism. 5. Verify the key with `GET /api/mcp/session`. 6. Retrieve live schemas with `GET /api/mcp/tools/list?includeDenied=true&includeSchemas=true`. 7. Choose a tool from `allowedToolNames`; never invent a tool name or argument. 8. Run a read-only tool first. 9. Explain the exact impact before any write, even when the MCP client does not provide a confirmation UI. 10. Use disposable records for mutation tests, clean them up, and revoke the temporary key. Pin the currently verified public package during reproducible tests: ```bash npx -y workestra-mcp@2.0.4 \ --api-key="$WORKESTRA_API_KEY" \ --api-url="https://platform.workestra.app" ``` See [MCP setup](/docs/integrations/mcp) for client-specific configuration and [Tool Discovery](/docs/integrations/mcp/tools) for the hosted endpoints. ## REST integration protocol 1. Confirm that the intended operation is listed in [Public API Status](/docs/api/status). 2. Read its endpoint guide. Do not derive fields from a route name. 3. Create a key with the documented scope. 4. Send a read-only request and record its response envelope. 5. Test validation with a disposable request. 6. For writes, identify whether the action is reversible, soft-delete, or permanent. 7. Add bounded retries only for network errors, `429`, and retryable `5xx`. 8. Do not retry `400`, `401`, `403`, `404`, or `422` unchanged. 9. Honor `Retry-After` and make retryable mutations idempotent in the caller. 10. Remove test data and revoke the temporary key. If an operation is not listed, use an equivalent permitted MCP tool or email support. Do not guess a body from database fields, UI labels, or another module. ## Authentication and secret handling API keys start with `wks_` and are workspace-bound: ```http Authorization: Bearer wks_example ``` The key must not appear in: - chat messages or prompts; - screenshots or screen recordings; - source code or committed `.env` files; - query strings or URLs; - support tickets or webhook payloads; - logs, traces, or analytics. Use one key per integration. Rotation means creating a replacement, testing it, and revoking the old key. ## Pre-write safety check Before an agent writes, it must be able to answer: 1. Which workspace will change? 2. Which tool or HTTP operation will run? 3. Which records and fields will change? 4. Is the operation reversible? 5. Is a duplicate request safe? 6. What permission authorizes it? 7. How will the result be verified? 8. How will test data be removed? If any answer is unknown, stop and retrieve the live schema, read the endpoint guide, or contact support. ## Error decision | Result | Agent action | | --- | --- | | `400` / `422` | Correct the request using the documented/live schema; do not blindly retry | | `401` | Verify secret storage, bearer format, expiry, revocation, and canonical host | | `403` | Inspect scopes/permissions; do not request broader access without explaining why | | `404` | Verify resource ID, workspace ownership, path, and whether the route/tool exists | | `409` | Read the conflict response and current resource state before deciding | | `429` | Honor `Retry-After`; use exponential backoff with jitter | | `5xx` | Retry only safe/idempotent operations within a bounded budget | | Missing MCP tool | Check `/api/mcp/session`, denied tools, features, and `--read-only` | | Ambiguous contract | Stop; do not infer fields | See [Troubleshooting](/docs/api/troubleshooting) for detailed diagnostics. ## Escalate to Workestra Email [support@workestra.app](mailto:support@workestra.app) with: - workspace ID, never the API key; - UTC timestamp; - REST method/path or MCP tool name; - HTTP status; - request, delivery, or correlation ID when present; - sanitized input and response body; - client and `workestra-mcp` version; - whether the failure is reproducible; - expected and actual behavior. Redact credentials, personal data not required for diagnosis, attachment URLs, and capability tokens. ## Definition of done An integration is ready when: - the key is least-privilege and separately revocable; - authentication and a read-only smoke test pass; - all used schemas are documented or retrieved live; - writes were tested against disposable data; - `401`, `403`, `429`, and retryable `5xx` behavior were exercised; - duplicate delivery/call behavior is safe; - logs contain no secrets; - cleanup and key rotation are documented. # Authentication Source: https://docs.workestra.app/docs/api/authentication Create Workestra API keys and understand REST scopes and MCP permissions. Third-party REST and MCP integrations authenticate with a workspace API key: ```http Authorization: Bearer wks_your_api_key ``` The first-party `/api/v1` routes also accept a verified Workestra session JWT. Use an API key for external integrations. ## Create an API key 1. Open **Settings > AI > External Connections > API Keys**. 2. Select **API Keys**. 3. Click **Create API Key**. 4. Name the key and choose the smallest useful access preset or scope set. 5. Optionally set an expiry date. 6. Copy the key immediately. It is shown only once. The canonical settings URL is: ```text https://platform.workestra.app/settings/ai?tab=connections ``` Standard keys currently start with `wks_`. ## REST example ```bash curl "https://platform.workestra.app/api/v1/crm/contacts?page=1&limit=10" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" \ -H "Accept: application/json" ``` ## REST scope catalog Write scopes also satisfy their matching read scope. | Module | Read scope | Write scope | | --- | --- | --- | | Support tickets | `tickets.read` | `tickets.write` | | CRM shared resources | `crm.read` | `crm.write` | | CRM contacts | `contacts.read` | `contacts.write` | | CRM deals | `deals.read` | `deals.write` | | Projects | `projects.read` | `projects.write` | | Issues/tasks | `issues.read` | `issues.write` | | Planning | `planning.read` | `planning.write` | | Assets | `assets.read` | `assets.write` | | Bookings | `bookings.read` | `bookings.write` | | Field service | `fsm.read` | `fsm.write` | | Goals | `goals.read` | `goals.write` | | Marketing | `marketing.read` | `marketing.write` | | Procurement | `procurement.read` | `procurement.write` | | Stock | `stock.read` | `stock.write` | | Subscriptions | `subscriptions.read` | `subscriptions.write` | | Surveys | `surveys.read` | `surveys.write` | | Time | `time.read` | `time.write` | Do not use older granular stock names such as `stock.products.read` or `stock.movements.write`; they are not valid key scopes. > **Info:** REST requests require a matching read or write scope. A matching write scope also satisfies reads for that area. If a valid key receives `403`, create or rotate to a key with the smallest scope listed by the endpoint guide. ## MCP permissions MCP tools use granular permissions such as `read_contacts`, `create_contacts`, `update_contacts`, and `delete_contacts`. The server derives those permissions from the key's scope preset unless the key stores an explicit permission map. Inspect the exact effective permissions and tools for a key: ```bash curl "https://platform.workestra.app/api/mcp/session" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` See [MCP tool discovery](/docs/integrations/mcp/tools) for the complete permission-aware tool list and schemas. ## Authentication failures | Status | Meaning | | --- | --- | | `401` | Missing, malformed, inactive, expired, or unknown key | | `403` | Valid key but the requested read, mutation, or tool needs another scope or permission | | `429` | Rate limit, monthly quota, or agent-trial tool quota reached | Workspace suspension, deletion, or lifecycle restrictions can also make an otherwise valid key unavailable. ## Revoke and rotate Revocation is immediate and irreversible. To rotate safely: 1. Create a replacement key. 2. Update the integration. 3. Verify the new key with `/api/mcp/session` or a read-only REST request. 4. Revoke the old key. Use separate keys per client, set expiries for temporary tests, and never place keys in URLs, screenshots, commits, browser bundles, or shared logs. # API Testing Guide Source: https://docs.workestra.app/docs/api/testing Safe smoke tests for Workestra REST and hosted MCP endpoints. This guide is designed for pre-launch integration tests against the current production contract. If an AI assistant is running the test, it must first read the [AI Agent Integration Guide](/docs/api/agent-guide) and must not ask for the key in chat. ## Set test variables ```bash export WORKESTRA_API_URL="https://platform.workestra.app" export WORKESTRA_API_KEY="wks_your_api_key" ``` PowerShell: ```powershell $env:WORKESTRA_API_URL = "https://platform.workestra.app" $env:WORKESTRA_API_KEY = "wks_your_api_key" ``` Use a temporary key with the smallest required scopes. Never paste a real key into screenshots, tickets, chat logs, or committed shell scripts. ## 1. Confirm authentication behavior Without a key: ```bash curl -i "$WORKESTRA_API_URL/api/v1/crm/contacts?limit=1" ``` Expected: HTTP `401`. With a key: ```bash curl -i "$WORKESTRA_API_URL/api/v1/crm/contacts?limit=1" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` Expected: HTTP `200`, JSON, and `X-API-Version: v1`. ## 2. Verify the key's MCP capability set ```bash curl "$WORKESTRA_API_URL/api/mcp/session" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` Check `allowedToolCount`, `deniedToolCount`, `allowedToolNames`, and `permissions.granted`. ## 3. Retrieve live tool schemas ```bash curl "$WORKESTRA_API_URL/api/mcp/tools/list?includeDenied=true&includeSchemas=true" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` This is the authoritative catalog for the tested key and deployed version. ## 4. Call a read-only MCP tool directly First choose a name from `allowedToolNames`. Example: ```bash curl -X POST "$WORKESTRA_API_URL/api/mcp/tools/call" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" \ -H "Content-Type: application/json" \ -d '}' ``` Expected success shape: ```json , "entities": [] } ``` ## 5. Test a REST mutation Use a disposable record: ```bash curl -X POST "$WORKESTRA_API_URL/api/v1/crm/contacts" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" \ -H "Content-Type: application/json" \ -d '' ``` The contacts create endpoint currently returns the created object directly. ## 6. Negative tests Run at least: - Missing bearer header → `401` - Invalid key → `401` - Valid key without required read permission → `403` - Valid key without required write permission → `403` - Unknown JSON field on a strict mutation → `400` or `422` - Unknown MCP tool → `404` - MCP tool denied by key → omitted from the default tool list or rejected by the call endpoint - Excess traffic → `429` with `Retry-After` ## Known test caveats - Use the `platform.workestra.app` origin directly to avoid bearer-header loss during redirects. - OpenAPI publication is temporarily paused. Use the dedicated endpoint guides and runtime validation. - `GET /api/v1/issues` defaults to project tasks unless `kind=ticket` is set. - Do not use `DELETE /api/v1/issues/` for support tickets. - Webhook delivery is asynchronous and can take up to 24 hours on the current service tier. ## Cleanup Delete disposable data through a supported route or the UI, then revoke the temporary API key after the test session. In PowerShell, remove the temporary process variables when finished: ```powershell Remove-Item Env:WORKESTRA_API_URL Remove-Item Env:WORKESTRA_API_KEY ``` If a test still fails after following [Troubleshooting](/docs/api/troubleshooting), email [support@workestra.app](mailto:support@workestra.app) with the workspace ID, UTC timestamp, operation, client version, status, and sanitized response. # Integration Recipes Source: https://docs.workestra.app/docs/api/recipes Safe end-to-end recipes for common Workestra REST and MCP integrations. These recipes show the integration sequence, not merely an isolated request. Use disposable records during testing. ## Connect an AI assistant through MCP 1. Create a temporary API key in **Settings > AI > External Connections > API Keys**. 2. Pin `workestra-mcp@2.0.4` in the client configuration. 3. Verify `/api/mcp/session`. 4. retrieve `/api/mcp/tools/list?includeDenied=true&includeSchemas=true`. 5. Run a permitted read tool. 6. Explain and run one reversible/disposable write. 7. verify the result with a read. 8. remove the test record and revoke the key. Full client configurations: [MCP Server](/docs/integrations/mcp). ## Synchronize CRM contacts Recommended REST scope: `contacts.read` for export-only or `contacts.write` for synchronization. 1. List contacts with `GET /api/v1/crm/contacts?page=1&limit=50`. 2. Continue while `pagination.hasMore` is true. 3. Store the Workestra contact ID in the external system. 4. Create only after searching by stable identifiers such as email. 5. Use `company_id` or `company_name`; do not send an undocumented `company` field. 6. Verify each write by reading the resulting contact. 7. Define conflict ownership before implementing bidirectional updates. See [Contacts](/docs/api/endpoints/contacts). ## Create a project and task Scopes: `projects.write` and `issues.write`. 1. Create the project with `POST /api/v1/projects`. 2. Save the returned project UUID. 3. Create the task with `POST /api/v1/issues`. 4. Set `kind: "task"` and the saved `project_id`. 5. Verify with `GET /api/v1/issues?kind=task&project_id=`. 6. Delete test tasks before deleting the project. Do not send `target_date` on projects or `labels` during task creation; those strict schemas reject unknown fields. ## Create a support ticket from a form Use the Support public API, not `/api/v1/issues`, for customer-facing intake. 1. For a trusted backend, create a key with `tickets.write`. 2. POST `name`, `email`, `subject`, optional `description`, and optional `type` to `/api/public/tickets`. 3. Let the key determine the workspace; do not expose the key in browser code. 4. Store the returned public ticket reference. 5. Use the public capability-token flow for customer tracking and replies. See [Support Developer API](/docs/modules/support/developer-api). ## Create and manage a booking For an AI integration, prefer the `bookings` MCP feature because its live tool schemas are complete for the deployed registry. 1. Grant only booking access. 2. Retrieve tools with `features=bookings`. 3. Read booking-link availability first. 4. Create a disposable booking using the returned schema. 5. Verify it appears in the booking list. 6. Cancel the test booking using the documented tool schema. The REST booking routes exist, but remain matrix-only and should not be guessed from the route names. ## Build a webhook receiver 1. Create a module-specific subscription in its settings UI or documented API. 2. Save the one-time secret. 3. Accept the raw request body. 4. reject timestamps outside a five-minute replay window. 5. Verify HMAC-SHA256 over `.`. 6. Deduplicate on `X-Workestra-Delivery-Id`. 7. Return `2xx` within 10 seconds. 8. Process longer work asynchronously. 9. Use the test-delivery action. 10. Account for daily production queue draining. See [Webhooks](/docs/api/webhooks). ## Production handoff checklist - Dedicated key and owner recorded - Minimal scopes - Expiry/rotation plan - Secret stored outside source control - Read and write smoke tests recorded - Cleanup completed - Retry budget bounded - Idempotency/deduplication implemented - Monitoring excludes secrets - Escalation contact: `support@workestra.app` # API and MCP Troubleshooting Source: https://docs.workestra.app/docs/api/troubleshooting Diagnose authentication, permissions, validation, rate limits, missing tools, webhooks, and transport failures. Start by recording the UTC time, operation, status, sanitized response, client version, and request/delivery ID. Never record the API key. ## Fast diagnostic sequence 1. Confirm the documentation URL is on `docs.workestra.app`. 2. Confirm API calls use `https://platform.workestra.app` directly. 3. Verify the bearer header is exactly `Authorization: Bearer wks_...`. 4. For MCP, call `/api/mcp/session`. 5. Retrieve the live tool/schema list. 6. Reproduce with the smallest read-only request. 7. Branch on the HTTP status below. ## HTTP errors ### 400 or 422: invalid request - Compare the request against the dedicated endpoint guide or live MCP schema. - Remove fields not explicitly accepted; many REST handlers use strict schemas. - Check UUIDs, ISO timestamps, enum casing, empty strings, and required `kind` fields. - Confirm `Content-Type: application/json` and valid JSON. - Do not assume the generic OpenAPI placeholder accepts arbitrary properties. ### 401: authentication failed - Confirm the key begins with `wks_`. - Confirm the header contains one `Bearer` prefix and no quotes. - Use `platform.workestra.app` directly; cross-host redirects may remove the header. - Check expiry, revocation, workspace state, and accidental whitespace. - Ensure the secret was added to the MCP/client process, not only the interactive shell. Test: ```bash curl -i "https://platform.workestra.app/api/mcp/session" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` ### 403: permission denied - The credential is valid but lacks the route scope or MCP permission. - Inspect `permissions.granted`, `allowedToolNames`, and denied tool metadata. - Check whether `--read-only` or `--features` filtered the local MCP registry. - Explain the missing permission before asking an Admin to replace the key. ### 404: route, tool, or resource not found - Verify the full path and HTTP method. - Use a supported route from the status page. - For MCP, retrieve `allowedToolNames`; unknown tools and denied tools differ. - Verify the resource belongs to the API key's workspace. - Remember that `www.workestra.app/docs/api` is not the documentation host; use `docs.workestra.app/docs/api`. ### 409: conflict Read the current resource before retrying. Typical causes include duplicate identifiers, invalid state transitions, concurrent updates, or already-consumed capabilities. ### 429: rate or quota limit - Honor `Retry-After`. - Add exponential backoff with jitter. - Keep a maximum retry count and total elapsed-time budget. - Reduce polling, cache reads, and use webhooks where their latency is acceptable. - A monthly CRM quota and per-minute route/MCP limits are different controls. ### 500-504: server or upstream failure - Retry only reads or known-idempotent writes. - Use a bounded retry budget. - Preserve the sanitized response and request ID. - Check [Known Contract Limitations](#known-contract-limitations) before escalating. ## MCP-specific failures ### The client shows no Workestra tools 1. Confirm the MCP process starts successfully. 2. Pin `workestra-mcp@2.0.4` for a reproducible test. 3. Confirm the API key is available to that process. 4. Call `/api/mcp/session` directly. 5. Remove `--features` temporarily. 6. Check whether `--read-only` is intentionally set. 7. Restart or reconnect the MCP server in the client. ### A documented tool is missing The deployed registry and key policy are authoritative. Retrieve: ```text GET /api/mcp/tools/list?includeDenied=true&includeSchemas=true ``` Check whether the tool is denied, filtered by feature, blocked by an agent-trial policy, or absent from the deployed tool version. ### Tool arguments are rejected Use the schema returned by `/api/mcp/tools/list`. Do not translate REST field names into MCP arguments or copy parameters from another tool. ### A write ran without a Workestra confirmation card That is expected for external MCP clients. Workestra's confirmation card belongs to the in-app AI surface. External agents must explain the write and obtain any required user approval before calling the tool. ## REST-specific failures ### OpenAPI-generated client accepts fields that runtime rejects OpenAPI publication is temporarily paused. Do not use a previously cached specification. Use the endpoint guide or live MCP schema until the sanitized download is linked from the OpenAPI status page. ### Response envelope differs Most v1 routes return ``, but several older create handlers return an object directly. Branch on the endpoint guide and actual status/body rather than assuming every route is identical. ### Issues return the wrong resource type Set `kind=task` or `kind=ticket` explicitly. An omitted kind currently defaults to project tasks. Do not use `/api/v1/issues/` DELETE for support tickets. ## Webhook failures ### Signature mismatch - Use the exact raw JSON bytes. - Sign `.`, not the body alone. - Use the secret for that subscription. - Compare the full `sha256=` value in constant time. ### Duplicate deliveries Deduplicate on `X-Workestra-Delivery-Id`. A network timeout can cause a successful receiver to see the same delivery again. ### Delivery is delayed Webhook delivery is asynchronous and can take up to 24 hours on the current service tier. A stored retry time does not guarantee minute-level execution. ### Receiver returns 4xx Except `429`, a `4xx` is treated as a permanent failure. Correct the receiver before generating another test event. ## Known contract limitations - OpenAPI publication is temporarily paused pending the sanitized application release. - Webhook delivery can take up to 24 hours on the current service tier. - Some webhook event names retain compatibility aliases; use the event name shown in delivery history and test payloads. - The Zapier integration is not currently available for production use. - `/api/v1/issues` DELETE supports project tasks, not support tickets. ## Contact support Email [support@workestra.app](mailto:support@workestra.app). Include: ```text Workspace ID: UTC timestamp: REST method/path or MCP tool: HTTP status: Request/delivery ID: Client and version: Expected behavior: Actual behavior: Sanitized request: Sanitized response: Reproduction steps: ``` Never include an API key, session token, approval token, capability token, private attachment URL, or unnecessary personal data. # Endpoints Overview Source: https://docs.workestra.app/docs/api/endpoints Supported resource guides for the Workestra REST API. Base URL: ```text https://platform.workestra.app/api/v1 ``` The supported public REST contract contains **7 paths and 17 operations**. | Resource | Paths | Guide | | --- | --- | --- | | CRM contacts | `/crm/contacts` | [Contacts](/docs/api/endpoints/contacts) | | CRM deals | `/crm/deals`, `/crm/deals/` | [Deals](/docs/api/endpoints/deals) | | Projects | `/projects`, `/projects/` | [Projects](/docs/api/endpoints/projects) | | Tasks and tickets | `/issues`, `/issues/` | [Issues](/docs/api/endpoints/issues) | ## Common behavior - Bearer authentication is required. - API-key reads require the matching read or write scope; mutations require the write scope. - Standard list pagination is `page` plus `limit`, with a usual default of 50 and maximum of 100. - Sorting and filtering are endpoint-specific. Do not send parameters unless the resource guide lists them. - Strict request schemas reject unknown fields on many mutations. - Most creates return `201`; updates and deletes normally return `200`. An operation absent from this page and [Public API Status](/docs/api/status) is not a supported public REST contract. Use [MCP](/docs/integrations/mcp) for broader automation or contact [support@workestra.app](mailto:support@workestra.app). # Contacts API Source: https://docs.workestra.app/docs/api/endpoints/contacts List and create CRM contacts. Base path: `/api/v1/crm/contacts` ## List contacts ```http GET /api/v1/crm/contacts?page=1&limit=50&search=Acme&status=active ``` | Parameter | Type | Notes | | --- | --- | --- | | `page` | integer | Default `1` | | `limit` | integer | Default `50`, maximum `100` | | `search` | string | Tokenized contact search | | `status` | string, repeatable | `active`, `inactive`, `blocked`, or `pending` | Example: ```bash curl "https://platform.workestra.app/api/v1/crm/contacts?search=Acme&limit=10" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` The response contains `data` and `pagination`. ## Create a contact ```http POST /api/v1/crm/contacts Content-Type: application/json ``` Requires `contacts.write`. ```json ``` `email` is the only required field. Accepted optional fields: | Field | Validation | | --- | --- | | `first_name`, `last_name` | Maximum 120 characters | | `phone` | Maximum 50 characters | | `job_title` | Maximum 180 characters | | `company_id` | UUID, empty string, or `null` | | `company_name` | Maximum 255 characters | | `contact_type` | `new`, `engaged`, `qualified`, `customer`, `inactive`, `lead`, `prospect`, `partner`, or `vendor` | | `status` | `active`, `inactive`, `blocked`, or `pending` | | `lead_source`, `industry` | Maximum 180 characters | | `notes` | Maximum 10,000 characters | | `tags` | At most 50 strings, each at most 100 characters | | `custom_fields` | JSON object | | `external_id` | Maximum 255 characters | | `country`, `state`, `city` | Maximum 120 characters | | `social_linkedin` | Maximum 500 characters | The body is strict: unknown fields such as `company` are rejected. Use `company_id` or `company_name`. The current create handler returns the created contact object directly with HTTP `201`, rather than wrapping it in ``. ## Update and delete There is currently no `/api/v1/crm/contacts/` REST route. Update and delete contacts through the application or an authorized MCP tool. # Deals API Source: https://docs.workestra.app/docs/api/endpoints/deals List, create, retrieve, update, and delete CRM deals. ## List deals ```http GET /api/v1/crm/deals ``` | Parameter | Type | Notes | | --- | --- | --- | | `page` | integer | Default `1` | | `limit` | integer | Default `50`, maximum `100` | | `status` | string, repeatable | `open`, `on_hold`, `closed_won`, `closed_lost` | | `stage` | string, repeatable | `discovery`, `qualified`, `proposal`, `negotiation`, `closed_won`, `closed_lost` | | `assignee` | UUID, repeatable | Assigned user | | `contact_id` | UUID | Associated contact | | `company_id` | UUID | Associated company | | `value_min` | number | Minimum value | | `value_max` | number | Maximum value | The response contains `data` and `pagination`. ## Create a deal ```http POST /api/v1/crm/deals Content-Type: application/json ``` Requires `deals.write`. ```json ``` `title` is required. Enum values are lowercase. Optional fields include `description`, `contact_id`, `company_id`, `assigned_to`, `status`, `stage`, `value`, `currency`, `probability`, `expected_close_date`, `actual_close_date`, `lost_reason`, `source`, `tags`, `custom_fields`, `external_id`, `price_book_id`, `package_id`, `rep_id`, `developer_id`, `commission_pct`, and `territory`. The body is strict and rejects unknown fields. ## Retrieve a deal ```http GET /api/v1/crm/deals/ ``` Returns `404` when the deal is not present in the authenticated workspace. ## Update a deal ```http PATCH /api/v1/crm/deals/ Content-Type: application/json ``` Requires `deals.write`. The body accepts the same optional fields as create and must contain at least one field. ## Delete a deal ```http DELETE /api/v1/crm/deals/ ``` Requires `deals.write`. The service performs the CRM deal deletion behavior and returns: ```json } ``` # Projects API Source: https://docs.workestra.app/docs/api/endpoints/projects Manage projects and inspect their cycles and tasks. ## Project routes | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/api/v1/projects` | Paginated project list | | `POST` | `/api/v1/projects` | Create a project | | `GET` | `/api/v1/projects/` | Retrieve one project | | `PATCH` | `/api/v1/projects/` | Update a project | | `DELETE` | `/api/v1/projects/` | Delete/soft-delete through the project service | | `GET` | `/api/v1/projects//cycles` | Paginated project cycles | | `POST` | `/api/v1/projects//cycles` | Create a cycle | | `GET` | `/api/v1/projects//issues` | Paginated project tasks | List routes support `page` and `limit`; `limit` defaults to `50` and is capped at `100`. ## Create a project ```http POST /api/v1/projects Content-Type: application/json ``` Requires `projects.write`. ```json ``` `name` is required and limited to 200 characters. Optional fields are `description`, `status`, `priority`, `progress`, `start_date`, `end_date`, `team_id`, `lead_user_id`, `template_id`, `deal_id`, `company_id`, `github_url`, `external_id`, and `hosted`. Accepted priority values are `low`, `medium`, `high`, and `urgent`. The API accepts legacy and current project status keys and normalizes them. If both dates are supplied, `end_date` must be on or after `start_date`. ## Update a project ```http PATCH /api/v1/projects/ Content-Type: application/json ``` Requires `projects.write`. Supply at least one create field. ## Create a project cycle ```http POST /api/v1/projects//cycles Content-Type: application/json ``` Requires `projects.write`. The route scopes the new cycle to the project ID in the path. ## Project tasks ```http GET /api/v1/projects//issues?page=1&limit=50 ``` Despite the historical `/issues` name, this project-scoped route returns project tasks associated with the project. # Issues, Tasks, and Tickets API Source: https://docs.workestra.app/docs/api/endpoints/issues Current compatibility API for project tasks and support tickets. The historical `/issues` API spans two resource types: project tasks and support tickets. Use `kind=task` or `kind=ticket` explicitly when listing. ## Routes | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/api/v1/issues` | List tasks or tickets | | `POST` | `/api/v1/issues` | Create a task or ticket | | `GET` | `/api/v1/issues/` | Retrieve a task or ticket | | `PATCH` | `/api/v1/issues/` | Update a task or ticket | | `DELETE` | `/api/v1/issues/` | Delete a project task; see limitation below | | `GET` | `/api/v1/issues//comments` | List comments | | `POST` | `/api/v1/issues//comments` | Add a comment | | `POST` | `/api/v1/issues/bulk-update` | Apply one patch to at most 500 issues | ## List ```http GET /api/v1/issues?kind=task&page=1&limit=50 ``` | Parameter | Type | Notes | | --- | --- | --- | | `page` | integer | Default `1` | | `limit` | integer | Default `50`, maximum `100` | | `project_id` | UUID | Project filter | | `status` | string | Exact status | | `kind` | `task` or `ticket` | Selects the physical table | | `search` | string | Searches title and description | > **Warning:** If `kind` is omitted, the current service defaults to project tasks; it does not merge tasks and tickets into one result. ## Create ```http POST /api/v1/issues Content-Type: application/json ``` Requires `issues.write`. ```json ``` Required fields: - `title`, maximum 500 characters - `kind`, either `task` or `ticket` Optional fields: `description`, `status`, `priority`, `project_id`, `assignee_id`, `due_at`, `parent_id`, `cycle_id`, and `estimate_hours`. ## Update ```http PATCH /api/v1/issues/ Content-Type: application/json ``` Requires `issues.write`. Supply at least one optional create field other than `kind`; the kind cannot be changed. ## Bulk update ```json } ``` `issueIds` accepts 1–500 UUIDs. Patch fields are `status`, `assignee_id`, `cycle_id`, `priority`, `due_at`, `start_date`, `epic_id`, `add_labels`, and `remove_labels`. ## Current delete limitation `DELETE /api/v1/issues/` currently soft-deletes project tasks only. Do not use it to delete a support ticket in today's tests; use the Support UI or an authorized ticket tool until the compatibility route is corrected. # Public API Status Source: https://docs.workestra.app/docs/api/status Supported Workestra REST paths, scopes, and current limitations. This page is the public support boundary for the Workestra REST API. It lists the operations an external integration may rely on after reading the dedicated guide. OpenAPI publication is temporarily paused; see [OpenAPI status](/docs/api/openapi). ## Supported contract | Resource | Path | Methods | API-key scope | | --- | --- | --- | --- | | Contacts | `/crm/contacts` | `GET`, `POST` | `contacts.read` / `contacts.write` | | Deals | `/crm/deals` | `GET`, `POST` | `deals.read` / `deals.write` | | Deal | `/crm/deals/` | `GET`, `PATCH`, `DELETE` | `deals.read` / `deals.write` | | Projects | `/projects` | `GET`, `POST` | `projects.read` / `projects.write` | | Project | `/projects/` | `GET`, `PATCH`, `DELETE` | `projects.read` / `projects.write` | | Tasks or tickets | `/issues` | `GET`, `POST` | `issues.read` / `issues.write` | | Task or ticket | `/issues/` | `GET`, `PATCH`, `DELETE` | `issues.read` / `issues.write` | All paths are relative to: ```text https://platform.workestra.app/api/v1 ``` A matching write scope also authorizes reads for that area. Authentication failures return `401`; a valid key without the required scope returns `403`. ## Important compatibility behavior - Set `kind=task` or `kind=ticket` explicitly when listing issues. - An omitted issue kind currently defaults to project tasks. - `DELETE /issues/` supports project tasks, not support tickets. - Some create operations return the created object directly instead of the common `` envelope; follow the endpoint guide. - Runtime validation and the endpoint guide remain authoritative. ## Operations not listed here An application route existing does not make it a supported external contract. Do not probe or call unlisted routes, infer payloads from UI behavior, or rely on internal implementation details. For broader coverage: 1. Use [MCP tool discovery](/docs/integrations/mcp/tools) to retrieve the live, permission-aware tool list and schemas. 2. Ask [support@workestra.app](mailto:support@workestra.app) whether a REST operation is available for your use case. Legacy compatibility functions are not recommended for new integrations. ## Last verification The supported REST list, scopes, agent guidance, and sanitized OpenAPI publication gate were verified on **2026-07-29**. # API Webhooks Source: https://docs.workestra.app/docs/api/webhooks Current outbound webhook delivery contract for Workestra modules. Workestra webhooks are module-owned outbound HTTP callbacks. They are not a single global API surface: availability, configuration, scope, and event names depend on the module. ## Current model When a module emits an event, Workestra: 1. Finds enabled webhook subscriptions in the same workspace whose `events` array contains the emitted event. 2. Applies module scoping when the module configured a scope column, such as `project_id`, `contract_id`, or `booking_link_id`. 3. Queues one delivery per matching subscription. 4. A background dispatcher processes due deliveries. 5. Each delivery is sent as an HTTP `POST` to the subscription URL. Webhook enqueue is additive. In the audited modules, business actions generally continue even if webhook enqueue fails. ## Shipped module bindings | Module | Supported scope | |---|---| | Projects | Workspace or project | | Time | Workspace | | Support | Workspace | | Scheduling | Workspace or booking link | | Contracts | Workspace or contract | | Procurement | Workspace | | Planning | Workspace | | Goals | Workspace | | Surveys | Workspace | | Subscriptions | Workspace | | Marketing | Workspace | Some modules have richer user-facing webhook settings than others. Treat webhook availability as module-specific and verify it in the module guide or workspace settings. ## Delivery payload Outbound deliveries are JSON. ```json } ``` | Field | Description | |---|---| | `id` | Delivery row id. Use this for idempotency. | | `event` | Module event name that matched the subscription. | | `workspace_id` | Workspace that emitted the event. | | `created_at` | Delivery row creation time. | | `payload` | Module-specific event payload. | The payload shape is event-specific. Do not assume the generic CRM/recruiting/finance examples from older docs apply to every module. ## Request headers Every delivery includes: | Header | Value | |---|---| | `Content-Type` | `application/json` | | `X-Workestra-Signature` | `sha256=` | | `X-Workestra-Event` | Event name | | `X-Workestra-Delivery-Id` | Delivery row id | | `X-Workestra-Timestamp` | Unix timestamp in seconds | | `X-Workestra-Module` | Module binding name, such as `projects` or `support` | ## Signature verification Workestra signs this string: ```text . ``` The signature is HMAC-SHA256 using the subscription secret, encoded as: ```text sha256= ``` Recommended receiver checks: 1. Read the raw request body before JSON parsing. 2. Reject timestamps older than about five minutes. 3. Compute HMAC-SHA256 over `.` with the subscription secret. 4. Constant-time compare the computed `sha256=` value with `X-Workestra-Signature`. 5. Store `X-Workestra-Delivery-Id` or the payload `id` to make processing idempotent. ```ts import crypto from "node:crypto"; function verifyWorkestraWebhook(opts: ): boolean .$`; const expected = "sha256=" + crypto.createHmac("sha256", opts.secret).update(signed).digest("hex"); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(opts.signature), ); } ``` ## Retry behavior The shared engine currently uses this policy: | Outcome | Behavior | |---|---| | HTTP `2xx` | Mark delivery `delivered`; clear `next_attempt_at`. | | HTTP `429` | Retry. | | HTTP `5xx` | Retry. | | Network error or timeout | Retry. | | Other HTTP `4xx` | Permanent failure. | | Webhook disabled before delivery | Mark failed with `webhook disabled`. | Attempts are capped at four total tries: the first attempt plus three retries. Retry delays are approximately: | Failed attempt | Next delay | |---|---| | 1 | 1 minute | | 2 | 5 minutes | | 3 | 30 minutes | | 4 | Permanent failure | Each request times out after 10 seconds by default. ## Delivery cadence Delivery is asynchronous and can take up to 24 hours on the current service tier. Retry delays are minimum delays; the next dispatcher run determines the actual attempt time. Receivers must deduplicate by `X-Workestra-Delivery-Id`. Workestra coordinates concurrent delivery processing, but network timeouts can still make the same event visible more than once. ## Event examples by module These event names are documented in code comments or emitted by current module actions. Module availability can differ by workspace and rollout status. | Module | Example events | |---|---| | Projects | `task.updated` from bulk issue updates; project-scoped or workspace-wide subscriptions. | | Time | `time_entry.created`, `time_entry.updated`, `time_entry.deleted`, `timer.started`, `timer.stopped`, `timesheet.submitted`, `timesheet.approved`, `timesheet.rejected`, `calendar_import.converted`, `invoice_lines.created`. | | Support | Support ticket events emitted by support services and inbound email handling, including ticket creation/customer reply flows. | | Scheduling | Booking lifecycle events such as created, approved, declined, cancelled, rescheduled, no-show, and payment-related events. | | Contracts | Contract lifecycle and public-view events emitted from contract actions and renewal cron. | | Procurement | `purchase_order.approved`, `vendor_bill.paid`. | | Planning | `allocation.created`, `allocation.updated`, `allocation.deleted`, `allocation.confirmed`, `role_placeholder.created`, `role_placeholder.staffed`, `capacity.alert`. | | Goals | `goal.created`, `goal.status_changed`, `goal.closed`, `cycle.opened`, `cycle.closed`. | | Surveys | `survey.response_submitted`, `survey.completed`. | | Subscriptions | `subscription.created`, `subscription.updated`, `subscription.cancelled`, `subscription.payment_failed`, `subscription.churned`, `subscription.plan_changed`. | | Marketing | `campaign.scheduled`, `campaign.sending`, `campaign.sent`, `campaign.bounce_threshold_breached`, `send.opened`, `send.clicked`, `send.unsubscribed`, `send.bounced`, `segment.resolved`. | ## What not to assume - Do not assume webhooks are configured from a single **Settings > API > Webhooks** page. - Do not assume static Workestra source IP ranges are published. - Do not assume five retries; the shared engine caps at four total attempts. - Do not assume failed webhooks automatically disable the subscription. - Do not assume every event in older docs exists on the current `/api/v1` surface. ## Receiver checklist 1. Respond with a `2xx` status only after the delivery is durably accepted. 2. Return `429` or `5xx` for transient failures you want retried. 3. Return other `4xx` statuses only for permanent failures. 4. Verify signatures against the raw body and timestamp. 5. Deduplicate by delivery id. 6. Keep handlers below the 10-second timeout; process long work asynchronously. ## Related docs - [API Authentication](/docs/api/authentication) - [Rate Limits](/docs/api/rate-limits) - [Endpoints](/docs/api/endpoints) - [OpenAPI](/docs/api/openapi) # Rate Limits and Quotas Source: https://docs.workestra.app/docs/api/rate-limits Current enforced limits for Workestra REST and MCP requests. Workestra currently has several independently enforced limits. There is not yet one universal plan-tier requests-per-minute policy for every `/api/v1` route. ## Hosted MCP The hosted MCP session, tool-list, and tool-call endpoints enforce: | Dimension | Limit | | --- | ---: | | Source IP | 600 requests per minute | | Workspace | 600 requests per minute | Responses include: ```text X-RateLimit-Limit X-RateLimit-Remaining X-RateLimit-Reset Retry-After ``` `Retry-After` is included on `429` responses. ## REST rate limiting REST enforcement is currently route-family specific: | Route set | Current behavior | | --- | --- | | Selected Time and newer module routes | Per-IP cap of 120/minute plus workspace read/write buckets | | Workspace read bucket used by those routes | 300/minute | | Workspace write bucket used by those routes | 60/minute | | Selected CRM reads | Monthly API-call quota metering | | Other v1 routes | Authentication and authorization apply, but no single shared per-minute limiter is guaranteed | Because adoption is not uniform, do not infer a limit for an endpoint that does not return rate-limit headers. ## Monthly API quota Selected CRM endpoints increment a workspace API-usage counter and can return: ```json ``` This response uses HTTP `429`, `X-Quota-Exceeded: api_calls_monthly`, and a `Retry-After` value. The monthly amount comes from the workspace's configured plan quota; it is not the same as a per-minute limit. ## Agent-trial quota Human-approved agent-trial credentials additionally have: - A seven-day credential lifetime. - A maximum of 250 successful tool-call consumption attempts under the current contract. - A guarded tool allowlist. The trial contract and capability manifest are authoritative if they specify a stricter value. ## Client behavior For reliable test clients: 1. Honor `Retry-After`. 2. Use exponential backoff with jitter for `429`, network errors, and retryable `5xx`. 3. Do not retry validation, authentication, or permission failures unchanged. 4. Cache reads and prefer webhooks over polling. 5. Deduplicate mutations with application-level idempotency where the endpoint supports it. Example: ```ts const response = await fetch(url, options); if (response.status === 429) ``` ## What is not currently promised The public contract does not currently promise: - Starter/Professional/Enterprise limits of 100/500/2,000 requests per minute. - A universal 50%-of-tier write limit. - A universal 10/minute bulk/export tier. - A self-service endpoint-specific rate-limit increase. - Rate-limit headers on every REST response. # Versions and Contract Changes Source: https://docs.workestra.app/docs/api/versioning REST, MCP, tool-registry, and documentation version compatibility. Workestra has several independently versioned integration layers. | Layer | Current contract | How to verify | | --- | --- | --- | | REST API | URL version `v1`, active | Path prefix and `X-API-Version` where emitted | | OpenAPI | Publication temporarily paused | [OpenAPI status](/docs/api/openapi) | | Public MCP adapter | `workestra-mcp@2.0.4` | Pin the npm version in the client | | Shared tool registry | Live, permission-aware catalog | `/api/mcp/session` and `/api/mcp/tools/list` | | Documentation | Dated per page | `last_updated` and the machine bundle | ## REST versioning REST uses URL-path versioning: ```text https://platform.workestra.app/api/v1/... ``` `v1` is the only active version in the application version schedule. Some v1 response helpers emit: ```text X-API-Version: v1 X-API-Latest-Version: v1 ``` Header emission is not uniform across every handler, so the path remains the authoritative version identifier. ## Contract maturity is separate from version A route being under `/api/v1` does not by itself make it a supported external contract. - **Guide** operations are listed in Public API Status and have dedicated documentation. - **Unlisted** operations are private or unsupported and must not be probed. - **Deprecated** operations should not be used for new integrations. See [Public API Status](/docs/api/status). ## MCP compatibility The local `workestra-mcp` package supplies the STDIO protocol adapter and tool registration. Workestra's hosted API performs authentication and execution. For reproducible tests: 1. Pin `workestra-mcp@2.0.4`. 2. record `/api/mcp/session` capability counts. 3. retrieve live schemas from `/api/mcp/tools/list`. 4. do not assume a count or schema from an older client cache. Hosted behavior can change without a client-package release when the existing tool name/schema remains compatible. New names or schema changes normally require an adapter release. ## Breaking-change handling Before changing an integration: - check the OpenAPI publication status and compare the current official download when available; - retrieve fresh MCP tool schemas; - read pages whose `last_updated` date changed; - exercise the read/write smoke tests; - verify deprecated routes and package versions. Workestra does not currently publish a guaranteed minimum public deprecation window. Supported integrations should email [support@workestra.app](mailto:support@workestra.app) if they require a contractual migration window. ## 2026-07-29 integration documentation release - Canonical operational origin changed in examples to `platform.workestra.app`. - Supported REST contract verified at 7 paths and 17 operations. - API-key catalog verified at 34 scopes. - MCP catalog guidance changed to require live discovery instead of a cached count. - Agent guide, recipes, troubleshooting, `llms.txt`, and full machine bundle added. - OpenAPI limited to the supported public contract and stripped of internal source and validator metadata. - Webhook daily-drain behavior and signature format corrected. - Zapier availability documented without exposing private route inventory. # OpenAPI Reference Source: https://docs.workestra.app/docs/api/openapi Generated specification for the supported Workestra REST contract. The sanitized OpenAPI publication is temporarily paused while the application release catches up with this documentation release. > **Warning:** Do not generate a client from a previously cached Workestra OpenAPI file. During today's tests, use the four dedicated endpoint guides and [Public API Status](/docs/api/status), or use live [MCP tool discovery](/docs/integrations/mcp/tools) for broader coverage. The next published OpenAPI document is constrained to the supported public REST contract: **7 paths and 17 HTTP operations** for contacts, deals, projects, and issues/tasks. Routes that are not listed in Public API Status are not a supported public REST contract. ## Publication requirements | Area | Coverage | | --- | --- | | Supported paths and methods | Complete | | Authentication | Bearer API key | | Path and discovered query parameters | Included | | Request fields | Generated from runtime validation where possible | | Common success and error envelopes | Included | | Response entity fields | Generic for some operations | | Support contact | `support@workestra.app` | Publication is gated until the generated file excludes private route inventory, source-file locations, validator identifiers, database names, and other implementation metadata. Those details are not required to integrate and are not part of the public contract. ## Use it safely 1. Wait for this page to expose an official download link before generating a client. 2. Generate a client only for operations present in that file. 3. Read the linked endpoint guide before sending a mutation. 4. Treat runtime `400` or `422` validation as authoritative if a generated schema is more permissive. 5. Send API keys only to `https://platform.workestra.app`. 6. Regenerate the client when the OpenAPI `info.version` changes. Do not infer undocumented fields, internal routes, or database structure from response data. For a missing operation, retrieve the live MCP catalog or email [support@workestra.app](mailto:support@workestra.app). # Human-approved Agent Trials Source: https://docs.workestra.app/docs/api/agent-trials Request an isolated Workestra evaluation for an AI agent without sharing an existing workspace. The agent-trial protocol lets an external AI agent request a temporary, isolated Workestra evaluation. A human owns the decision: the agent cannot approve itself, accept legal terms for a person, or gain access to an existing workspace. ## Canonical contract - Capability manifest: `/.well-known/agent-access.json` - OpenAPI contract: `/openapi/agent-trials.json` - Challenge: `GET /api/agent-trials/challenge` - Request: `POST /api/agent-trials` - Human approval: `GET|POST /api/agent-trials/approve` - Agent status and one-time key exchange: `GET /api/agent-trials/status` - Authenticated tool surface: `/api/mcp` Treat the published manifest and OpenAPI document as the source of truth for request fields and current limits. Canonical operational origin: `https://platform.workestra.app`. ## Safe flow 1. Read the capability manifest. 2. Request and solve the short-lived reasoning challenge. 3. Submit the human owner's email, requested workspace name, agent identity, and declared purpose. 4. Store the returned request token in the agent runtime's secret store. 5. Ask the human to review the Workestra email, sign in with the same address, and approve or deny the isolated trial. 6. Poll the status endpoint with exponential backoff. 7. The first successful response after approval returns the API key exactly once. 8. Use the authenticated tools-list response as the exact allowed capability set. Approval links expire after 24 hours. Issued trial credentials expire after seven days and are limited to 250 tool calls unless the current contract states a stricter limit. ## Guardrails - Never ask the user to paste an approval token, session token, or Workestra API key into chat. - Never print credentials in logs, traces, screenshots, or generated files. - Never claim approval until the status endpoint confirms it. - Stop on failed, expired, denied, or revoked terminal states. - Do not bypass rate limits or unavailable capabilities. - A trial provisions a fresh workspace; it does not expose an existing customer workspace. ## Status polling Use the request token as a bearer credential. Start with a two-second interval, back off to at most 30 seconds, and honor `Retry-After`. The one-time key response must be persisted before the next poll. ## Related references - [Authentication](/docs/api/authentication) - [API rate limits](/docs/api/rate-limits) - [OpenAPI](/docs/api/openapi) # MCP Server Source: https://docs.workestra.app/docs/integrations/mcp Connect Codex, Claude, Cursor, VS Code, Windsurf, and other MCP clients to Workestra using the public workestra-mcp server. ## MCP Server Workestra provides a public MCP server for AI tools such as Codex, Claude Code, Claude Desktop, Cursor, VS Code, and Windsurf. The MCP server exposes a broad tool catalog. The exact tools visible to a client are filtered by its API-key permissions, optional `--features` selection, and optional `--read-only` mode. Retrieve the live catalog for every integration session rather than relying on a cached count. ## Compatibility contract | Component | Current documented contract | | --- | --- | | Public npm adapter | `workestra-mcp@2.0.4` | | Client transport | Local STDIO process | | Hosted execution API | `https://platform.workestra.app/api/mcp` | | Tool registry | Live, permission-aware catalog | | Per-key source of truth | `/api/mcp/session` and `/api/mcp/tools/list` | | Integration support | `support@workestra.app` | The deployed session/list responses override documentation counts when versions differ. Record the adapter version and capability counts in test logs. > **Warning:** `workestra-mcp@2.0.4` predates the Platform hostname migration. Configure `https://platform.workestra.app` explicitly with `--api-url` or `WORKESTRA_API_URL`; do not rely on that release's built-in default. ## What You Need You only need: 1. A Workestra API key from your workspace. 2. An MCP client such as Codex, Claude, Cursor, VS Code, or Windsurf. 3. The public npm package: `workestra-mcp`. You do **not** need to install or host `workestra-tools`. It is bundled into `workestra-mcp` at build time. ## Create an API Key 1. Open [Settings → AI → External Connections](https://platform.workestra.app/settings/ai?tab=connections). 2. Click **Create API Key**. 3. Name the key, for example `Codex MCP` or `Claude Code MCP`. 4. Choose a permission preset: - **MCP Default** for normal agent access. - **Read Only** if the assistant should only view data. 5. Set an expiry date if the key is temporary. 6. Copy the key immediately. It starts with `wks_` and is only shown once. Keep this key private. Do not paste it into public chat logs, Git commits, screenshots, or support tickets. ## How It Works ```text AI client → local workestra-mcp adapter → authenticated Workestra MCP API ``` The local MCP package is a thin adapter. It registers the Workestra tool names and schemas with your AI client, then forwards tool calls to Workestra's hosted API. The workspace API key is the only secret configured in the client; the Platform URL is non-secret connection configuration. Workestra's private service credentials remain server-side. ## Codex Setup: Choose STDIO In Codex, open **Connect to a custom MCP** and choose **STDIO**. Do **not** choose **Streamable HTTP** for Workestra. Workestra uses the local `npx` MCP adapter, so Codex must launch it with STDIO. ### Where to Find the Values All values are fixed except your Workestra API key: | Codex field | What to enter | Where it comes from | | -------------------------------- | ----------------------- | ------------------------------------------------ | | Name | `workestra` | Fixed value | | Transport tab | `STDIO` | Select the STDIO tab in Codex | | Command to launch | `npx` | Fixed value | | Arguments | `-y`, `workestra-mcp` | Fixed values | | Environment variable key | `WORKESTRA_API_URL` | Fixed value | | Environment variable value | `https://platform.workestra.app` | Fixed value | | Environment variable key | `WORKESTRA_API_KEY` | Fixed value | | Environment variable value | `wks_your_api_key_here` | Copy it from Workestra after creating an API key | | Environment variable passthrough | Leave blank | Nothing needed | | Working directory | Leave as default | Nothing needed | ### Codex Field Reference Fill the Codex screen exactly like this: | Field | Value | | -------------------------------- | --------------------------------------------- | | Name | `workestra` | | Type | `STDIO` | | Command to launch | `npx` | | Arguments | `-y`, `workestra-mcp` | | Environment variables | `WORKESTRA_API_URL` = `https://platform.workestra.app` | | Environment variables | `WORKESTRA_API_KEY` = `wks_your_api_key_here` | | Environment variable passthrough | Leave blank | | Working directory | Leave as default | ### Prompt to Give Codex If you want Codex to help you set it up, copy this prompt: ```txt Connect Workestra as a custom MCP server in Codex. Use STDIO. Do not use Streamable HTTP. Fill the Codex fields like this: Name: workestra Command to launch: npx Arguments: -y workestra-mcp Environment variables: WORKESTRA_API_URL=https://platform.workestra.app WORKESTRA_API_KEY=wks_your_api_key_here Environment variable passthrough: leave blank Working directory: leave as default After adding it, reconnect or restart the MCP server and verify that Workestra tools are available. Do not print or expose the API key. ``` ## Claude Code Setup Run this command: ```bash claude mcp add workestra -- npx -y workestra-mcp --api-key=wks_your_api_key_here --api-url=https://platform.workestra.app ``` ### Prompt to Give Claude Code If you want Claude Code to install it for you, copy this prompt: ```txt Install the Workestra MCP server for Claude Code. Use this command: claude mcp add workestra -- npx -y workestra-mcp --api-key=wks_your_api_key_here --api-url=https://platform.workestra.app After installing it, verify that the Workestra MCP server is listed and that Workestra tools are available. Do not print or expose the API key. ``` ## Claude Desktop Setup Add this to `claude_desktop_config.json`: ```json } } ``` ## Cursor Setup Add this to `~/.cursor/mcp.json`: ```json } } } ``` ## VS Code Setup Add this to `.vscode/mcp.json` in your workspace: ```json } } } ``` ## Windsurf Setup Add this to `~/.codeium/windsurf/mcp_config.json`: ```json } } } ``` ## Other MCP Clients Use the same pattern: ```json } ``` The server also accepts `--api-key=wks_your_api_key_here` as a CLI flag. ## CLI Options ```bash npx -y workestra-mcp [options] ``` | Option | Description | | ----------------- | ------------------------------------------------------- | | `--api-key=KEY` | Workestra API key. Alternative to `WORKESTRA_API_KEY`. | | `--api-url=URL` | Workestra API URL. Set this to `https://platform.workestra.app` when using `2.0.4`. | | `--read-only` | Register only read tools. | | `--features=LIST` | Comma-separated feature groups. Defaults to all groups. | | `--version` | Show the MCP package version. | | `--help` | Show help. | Environment variables: | Variable | Description | | ------------------- | --------------------------------------------------------- | | `WORKESTRA_API_KEY` | Workestra API key. | | `WORKESTRA_API_URL` | Workestra API URL. Use `https://platform.workestra.app`. | The current public npm release verified on 2026-07-29 is `workestra-mcp@2.0.4`. For reproducible tests, pin it: ```bash npx -y workestra-mcp@2.0.4 \ --api-key=wks_your_api_key_here \ --api-url=https://platform.workestra.app ``` Use unpinned `workestra-mcp` when you intentionally want npm's newest release. ## Hosted API used by the adapter The STDIO package validates the key and forwards calls to: | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/api/mcp/session` | Validate the key and return its effective permissions and allowed tool names | | `GET` or `POST` | `/api/mcp/tools/list` | Return permission-aware tool metadata and optional JSON schemas | | `POST` | `/api/mcp/tools/call` | Execute one allowed tool | These are hosted Workestra endpoints, not a Streamable HTTP MCP transport. The client still connects to `workestra-mcp` over STDIO. See [Tool discovery and direct testing](/docs/integrations/mcp/tools). ## Feature Groups The default setup exposes all feature groups allowed by your API key permissions. | Feature group | Tool count | | --------------- | ---------: | | `contacts` | 5 | | `deals` | 6 | | `companies` | 5 | | `activities` | 5 | | `pipeline` | 3 | | `invoicing` | 9 | | `tickets` | 13 | | `projects` | 14 | | `analytics` | 12 | | `recruiting` | 8 | | `knowledge` | 5 | | `quotations` | 6 | | `workspace` | 7 | | `email` | 4 | | `people` | 11 | | `expenses` | 5 | | `banking` | 3 | | `credit_notes` | 4 | | `payments` | 3 | | `peppol` | 3 | | `time` | 10 | | `bookings` | 14 | | `planning` | 15 | | `assets` | 16 | | `contracts` | 11 | | `order_forms` | 2 | | `procurement` | 14 | | `stock` | 17 | | `subscriptions` | 21 | | `surveys` | 10 | | `goals` | 13 | | `fsm` | 28 | | `marketing` | 18 | | `automations` | 17 | | `sequences` | 19 | Example: only expose CRM basics: ```bash npx -y workestra-mcp --api-key=wks_your_api_key_here --features=contacts,deals,companies,activities,pipeline ``` Example: read-only mode: ```bash npx -y workestra-mcp --api-key=wks_your_api_key_here --read-only ``` ## Permissions Every tool is checked against the permissions on your Workestra API key. For example: | Permission | Allows | | ----------------- | ------------------------------------------------------- | | `read_contacts` | Search and view contacts. | | `create_contacts` | Create contacts. | | `update_contacts` | Update contacts. | | `delete_contacts` | Delete contacts. | | `read_deals` | List deals, view deals, and read deal analytics. | | `create_deals` | Create deals. | | `update_deals` | Update deals. | | `read_invoices` | List invoices, view invoices, and read invoice reports. | | `create_invoices` | Create invoices. | | `read_tickets` | List and view support tickets. | | `create_tickets` | Create support tickets. | | `update_tickets` | Update support tickets. | Use **Read Only** if you want the assistant to answer questions but not change data. `--read-only` is a local registration filter: write tools are not presented to the MCP client. Server-side API-key permissions are still enforced on every call and remain the security boundary. ## Security Best Practices - Use one API key per AI client. - Prefer read-only keys for exploration and reporting. - Give write permissions only when the workflow requires them. - Set expiry dates for temporary access. - Revoke keys immediately if a device or AI client is compromised. - Do not paste API keys into public prompts, screenshots, commits, or shared documents. ## Testing the Connection After setup, restart or reconnect the MCP server in your AI client. Then try: - "Show me my pipeline summary." - "Search for contacts named John." - "List open support tickets assigned to me." - "Show overdue invoices this month." - "Find candidates for the React developer role." If the assistant says no Workestra tools are available, check: 1. The MCP server name is `workestra`. 2. The command is `npx`. 3. The arguments are `-y` and `workestra-mcp`. 4. The API key is set as `WORKESTRA_API_KEY`. 5. The API key has the permissions required by the tool you are trying to use. 6. `GET /api/mcp/session` returns the expected `allowedToolNames`. 7. The tested npm version is the version you intended to run. For schema-level diagnostics without an MCP client, use the commands in [Tool discovery and direct testing](/docs/integrations/mcp/tools). ## Still blocked? Use [API and MCP Troubleshooting](/docs/api/troubleshooting). If the diagnostic sequence does not resolve the failure, email [support@workestra.app](mailto:support@workestra.app) with the workspace ID, UTC timestamp, client and adapter version, tool name, sanitized error, and reproduction steps. Never include the API key. ## Publishing and Updates End users do not publish anything. They run the public npm package with `npx`. Workestra publishes `workestra-mcp`. When Workestra adds new tool names or changes tool schemas, a new package version is published. If Workestra only changes the behavior of an existing tool, users normally only need the hosted Workestra API update. # Tool Discovery and Testing Source: https://docs.workestra.app/docs/integrations/mcp/tools Retrieve the complete permission-aware Workestra tool catalog and test hosted MCP calls. Workestra exposes a broad, versioned tool catalog. A specific API key sees only the subset allowed by its effective permissions. Always retrieve the live catalog instead of relying on a cached tool count. The hosted discovery API is the source of truth for: - Tool names and descriptions - Read/write classification - Feature group - Required permission and legacy permission aliases - Whether the tested key is allowed to call the tool - JSON input schema ## Verify the session ```bash curl "https://platform.workestra.app/api/mcp/session" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` Response: ```json , "capabilities": } ``` The total reflects the deployed registry. Allowed/denied counts and names are illustrative and depend on the tested key. ## List tools ```http GET /api/mcp/tools/list Authorization: Bearer wks_... ``` Query parameters: | Parameter | Default | Meaning | | --- | --- | --- | | `includeDenied` | `false` | Include tools the key cannot call | | `includeSchemas` | `true` | Include each tool's JSON input schema | | `readOnly` | `false` | Filter out write tools | | `features` | all | Comma-separated feature groups | Complete audit request: ```bash curl "https://platform.workestra.app/api/mcp/tools/list?includeDenied=true&includeSchemas=true" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` Read-only CRM subset: ```bash curl "https://platform.workestra.app/api/mcp/tools/list?readOnly=true&features=contacts,deals,companies" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` `POST /api/mcp/tools/list` accepts the same options as JSON: ```json ``` ## Call a tool directly ```http POST /api/mcp/tools/call Authorization: Bearer wks_... Content-Type: application/json ``` ```json } ``` Use the input schema returned by `/tools/list`; do not guess argument names. Success: ```json , "entities": [ ] } ``` ## Feature groups Feature groups span CRM, projects, support, finance, people, scheduling, operations, reporting, and automation. Use the `allowedFeatures` and `allowedToolNames` returned for the current credential as the authoritative inventory. This avoids stale integrations as tools are added or permissions change. ## Rate limits The session, list, and call endpoints currently enforce: - 600 requests/minute per source IP - 600 requests/minute per workspace On `429`, honor `Retry-After` and the `X-RateLimit-*` headers. ## Errors | Status | Meaning | | --- | --- | | `400` | Invalid JSON, schema validation failure, executor failure, or other call error | | `401` | Missing, invalid, inactive, or expired API key | | `403` | Tool blocked for a guarded agent trial or permission missing | | `404` | Unknown tool name | | `429` | IP/workspace rate limit or agent-trial quota reached | ## Agent-trial differences Agent-trial keys: - Use a guarded tool allowlist. - Exclude high-risk external side effects and administrative capabilities. - Expire after seven days under the current contract. - Are capped at 250 tool calls under the current contract. Always trust `/api/mcp/session` and `/api/mcp/tools/list` for the actual tested credential. For unresolved permission or schema discrepancies, follow [API and MCP Troubleshooting](/docs/api/troubleshooting) or email [support@workestra.app](mailto:support@workestra.app) with the tool name, adapter version, workspace ID, and sanitized response. Never send the key. ## Testing checklist 1. Pin or record the `workestra-mcp` npm version. 2. Confirm `/api/mcp/session` succeeds. 3. Store the returned `allowedToolNames`. 4. Retrieve schemas with `/api/mcp/tools/list`. 5. Call a read tool with known-safe arguments. 6. Verify a denied or unknown tool fails as expected. 7. Test one disposable write only after confirming the permission and cleanup path. 8. Revoke the temporary key after testing. # Zapier Integration Source: https://docs.workestra.app/docs/integrations/zapier Availability and safe alternatives for connecting Workestra to Zapier. > **Warning:** The Workestra Zapier connector is not currently available for production integrations or end-to-end testing. Do not attempt to discover or call its private implementation endpoints. ## Recommended alternatives Choose one of these supported paths: 1. Use [MCP](/docs/integrations/mcp) when an AI assistant should inspect or update Workestra. 2. Use a documented [REST endpoint](/docs/api/endpoints) for a conventional integration. 3. Use a module [webhook](/docs/api/webhooks) to deliver supported events to a public HTTPS receiver. 4. Email [support@workestra.app](mailto:support@workestra.app) with the Zapier trigger or action you need and the intended test date. Do not enter a production API key into an unpublished or community Zapier app claiming to support Workestra. ## Availability checklist When Workestra announces a supported Zapier release, verify: - the connector is distributed through an official Workestra channel; - its authentication test succeeds with a temporary least-privilege key; - each trigger and action appears in current public documentation; - test records can be cleaned up; - revoking the key stops subsequent Zap runs. ## Related documentation - [REST API](/docs/api) - [Authentication](/docs/api/authentication) - [MCP](/docs/integrations/mcp) - [Webhooks](/docs/api/webhooks) # API Keys Source: https://docs.workestra.app/docs/modules/support/api-keys Create scoped, revocable credentials for the REST API, hosted MCP, and Support public API. Workestra API keys are workspace-bound bearer credentials. The same key format is used by the REST API, hosted MCP endpoints, the `workestra-mcp` package, and authenticated Support public-API calls. ## Create a key > **Info:** You must be a workspace Admin or Owner. 1. Open **Settings > AI > External Connections > API Keys**. 2. Select **API Keys**, then create a key. 3. Give the key a name and select only the scopes the integration needs. 4. Copy the plaintext value immediately. Workestra does not show it again. Keys start with `wks_`. Send one on every authenticated request: ```http Authorization: Bearer wks_example_key ``` The legacy **Support > Settings > API Keys** screen manages the same workspace keys, but **Settings > AI > External Connections** is the canonical location. ## Available scopes Workestra currently defines 34 scopes: read/write pairs for 17 API areas. | Area | Read scope | Write scope | | --- | --- | --- | | Support tickets | `tickets.read` | `tickets.write` | | CRM | `crm.read` | `crm.write` | | Contacts | `contacts.read` | `contacts.write` | | Deals | `deals.read` | `deals.write` | | Projects | `projects.read` | `projects.write` | | Project tasks / issues | `issues.read` | `issues.write` | | Planning | `planning.read` | `planning.write` | | Assets | `assets.read` | `assets.write` | | Bookings | `bookings.read` | `bookings.write` | | Field service | `fsm.read` | `fsm.write` | | Goals | `goals.read` | `goals.write` | | Marketing | `marketing.read` | `marketing.write` | | Procurement | `procurement.read` | `procurement.write` | | Stock | `stock.read` | `stock.write` | | Subscriptions | `subscriptions.read` | `subscriptions.write` | | Surveys | `surveys.read` | `surveys.write` | | Time | `time.read` | `time.write` | > **Info:** REST reads require a matching read or write scope. Mutations require the matching write scope. Always issue the smallest scope set needed by the integration and verify denied operations return `403`. For the Support public API specifically: - `tickets.read` authorizes `GET /api/public/tickets`. - `tickets.write` authorizes ticket creation and replies. - Authenticated requests are always restricted to the key's workspace. ## Responses - `401` means the key is missing, malformed, expired, or revoked. - `403` means the key is valid but lacks a required scope. ## Revoke or rotate Revocation takes effect on subsequent requests and cannot be undone. To rotate without downtime: 1. Create a second key with the same minimal scopes. 2. update the integration and verify it. 3. revoke the old key. Use one key per integration, keep it in a secrets manager or uncommitted environment file, and never place it in browser code. ## Related documentation - [Authentication](/docs/api/authentication) - [API status and scopes](/docs/api/status) - [Support Developer API](/docs/modules/support/developer-api) - [MCP integration](/docs/integrations/mcp) # Support Developer API Source: https://docs.workestra.app/docs/modules/support/developer-api Create and read support tickets, add replies, submit CSAT, and search the public knowledge base. The Support public API serves customer-facing ticket and knowledge-base flows. It is separate from the general `/api/v1` API. ```text https://platform.workestra.app/api/public ``` Use the `platform.workestra.app` hostname directly. The apex and `www` hostnames are marketing surfaces, and some HTTP clients remove `Authorization` when following a cross-host redirect. ## Authentication modes | Mode | Use | | --- | --- | | API key | Server-to-server ticket creation, listing, lookup, and replies | | Capability token | Customer ticket tracking, replies, reopening, and CSAT | | Unauthenticated | Ticket creation with `workspace_id`, KB search, and KB click telemetry | API-key requests use `Authorization: Bearer wks_...`. Customer tokens are issued by Workestra and must be treated as secrets. ## Endpoint summary | Method | Path | Authentication | | --- | --- | --- | | `POST` | `/api/public/tickets` | Optional API key; otherwise public and rate-limited | | `GET` | `/api/public/tickets` | `tickets.read` key, or `t` capability token | | `POST` | `/api/public/tickets/` | `tickets.write` key, or token in the body | | `PATCH` | `/api/public/tickets/` | Token in the body; reopens a ticket | | `POST` | `/api/public/tickets//feedback` | One-time CSAT token in the body | | `GET` | `/api/public/kb/search` | Public | | `POST` | `/api/public/kb/click` | Public | The identifier in the ticket subpath is the public `external_ticket_id`, such as `TKT-a1b2c3`. ## Create a ticket ```bash curl -X POST https://platform.workestra.app/api/public/tickets \ -H "Authorization: Bearer $WORKESTRA_API_KEY" \ -H "Content-Type: application/json" \ -d '' ``` With an API key, Workestra derives `workspace_id` from the key. Without a key, `workspace_id` is required in the JSON body. | Field | Required | Validation | | --- | --- | --- | | `workspace_id` | Public call only | UUID | | `name` | Yes | 1-200 characters | | `email` | Yes | Valid email | | `subject` | Yes | 1-200 characters | | `description` | No | Up to 5,000 characters | | `type` | No | `support_ticket`, `customer_request`, `bug_report`, or `feature_request` | | `attachments` | No | Up to 3 validated upload descriptors, each at most 50 MB | The route does not accept `title`, `customer_email`, `priority`, `channel`, `cc_emails`, or arbitrary `metadata`. ## Read tickets API-key list: ```bash curl "https://platform.workestra.app/api/public/tickets?limit=50&offset=0" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` Use `?id=` for one ticket. `limit` defaults to 50 and is capped at 100. Customer tracking uses the root endpoint, not a `GET /tickets/` route: ```text GET /api/public/tickets?t=&ticket= ``` Token reads return the token holder's ticket list, the selected ticket, and public comments. Internal comments are excluded. ## Reply or reopen Add a reply: ```json POST /api/public/tickets/TKT-a1b2c3 ``` An API key with `tickets.write` may omit `token`. `content` is 1-5,000 characters and up to three attachments are accepted. Reopen: ```json PATCH /api/public/tickets/TKT-a1b2c3 ``` ## Submit CSAT ```json POST /api/public/tickets/TKT-a1b2c3/feedback ``` `score` is an integer from 1 to 5 and `comment` is limited to 2,000 characters. The CSAT token is one-time and is consumed transactionally. ## Knowledge base ```text GET /api/public/kb/search?workspace_id=&q=reset%20password&limit=5 ``` `limit` defaults to 5 and is capped at 10. The route is public and CORS-enabled. ```json POST /api/public/kb/click ``` Click tracking accepts a query up to 200 characters and intentionally returns success even if telemetry storage fails. ## Public-route rate limits | Operation | Limit | | --- | --- | | Anonymous ticket creation | 10 per IP per hour | | Token ticket lookup | 20 per IP per minute | | Token ticket reply | 20 per IP per hour | | CSAT submission | 20 per IP per hour | | KB search | 5 per IP per minute | | KB click | 30 per IP per minute | Authenticated ticket creation, reads, and replies skip these anonymous IP limiters. See [Rate Limits](/docs/api/rate-limits) for the separate `/api/v1` and MCP policies. ## Errors Support public routes return a top-level `error` string, sometimes with `details`; they do not use the general `/api/v1` response envelope. Expect `400`, `401`, `403`, `404`, `429`, and `500` depending on validation and authorization. ## Related documentation - [API Keys](/docs/modules/support/api-keys) - [REST API reference](/docs/api) - [Support Webhooks](/docs/modules/support/webhooks) # Support Outbound Webhooks Source: https://docs.workestra.app/docs/modules/support/webhooks Queue and verify signed Support ticket-event deliveries. Support webhooks enqueue ticket events for delivery to an HTTPS endpoint. > **Warning:** Delivery is asynchronous and can take up to 24 hours on the current service tier. Use the test-delivery action for immediate endpoint validation. ## Configure An Admin or Owner can open **Support > Settings > Webhooks**, add an HTTPS URL, choose events, enable the webhook, and copy its generated secret. The current event registry contains: - `ticket.created` - `ticket.updated` - `ticket.field_changed` - `ticket.status_changed` - `ticket.priority_changed` - `ticket.assigned` - `ticket.label_added` - `ticket.label_removed` - `ticket.customer_replied` - `ticket.agent_responded` - `ticket.escalated` - `ticket.resolved` - `ticket.closed` - `ticket.deleted` - `ticket.sla_warning` - `ticket.sla_breached` - `ticket.reply_scheduled` - `ticket.scheduled_reply_sent` - `ticket.scheduled_reply_cancelled` - `webhook.test` Event producers are implemented across different write paths. Before relying on an event for a test, perform its matching UI/API action and confirm a delivery row appears. ## Delivery headers Workestra sends: ```text X-Workestra-Signature: sha256= X-Workestra-Timestamp: X-Workestra-Event: X-Workestra-Delivery-Id: X-Workestra-Module: support ``` The signed message is: ```text . ``` Verify the HMAC-SHA256 using the webhook secret and compare in constant time: ```js import crypto from "node:crypto"; export function verifyWorkestraWebhook(rawBody, headers, secret) .$`; const expected = "sha256=" + crypto.createHmac("sha256", secret).update(signed).digest("hex"); if (!supplied || supplied.length !== expected.length) return false; return crypto.timingSafeEqual( Buffer.from(supplied), Buffer.from(expected), ); } ``` Reject stale timestamps (five minutes is a reasonable replay window) and deduplicate on `X-Workestra-Delivery-Id`. ## Success, failure, and retries - `2xx`: delivered. - `429`, `5xx`, network error, or 10-second timeout: retryable. - Other `4xx`: permanent failure. - Maximum: four attempts total. - Stored retry offsets: 1, 5, and 30 minutes after successive failures. Because the production drain is daily, those minute-level due times do not guarantee minute-level retry delivery; a due row waits for the next worker run. ## Testing 1. Create and enable a webhook in a disposable workspace. 2. copy the secret. 3. use **Send test** and verify `webhook.test`. 4. verify all five Workestra headers and the timestamp-prefixed signature. 5. return a `2xx` within 10 seconds and process asynchronously. 6. test deduplication using the delivery ID. 7. inspect delivery history for status and errors. ## Related documentation - [General webhook contract](/docs/api/webhooks) - [Support Developer API](/docs/modules/support/developer-api) - [API Keys](/docs/modules/support/api-keys) # Projects REST API Source: https://docs.workestra.app/docs/modules/projects/integrations/rest-api Manage projects and project tasks through the Workestra v1 API. Projects are exposed at `/api/v1/projects`; project tasks use the historical `/api/v1/issues` resource name. ```bash export WORKESTRA_API_KEY="wks_..." curl "https://platform.workestra.app/api/v1/projects?page=1&limit=25" \ -H "Authorization: Bearer $WORKESTRA_API_KEY" ``` See [Authentication](/docs/api/authentication) for key creation and JWT support. ## Projects | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/api/v1/projects` | Paginated project list | | `POST` | `/api/v1/projects` | Create a project | | `GET` | `/api/v1/projects/` | Read a project | | `PATCH` | `/api/v1/projects/` | Update a project | | `DELETE` | `/api/v1/projects/` | Soft-delete a project | Create example: ```bash curl -X POST https://platform.workestra.app/api/v1/projects \ -H "Authorization: Bearer $WORKESTRA_API_KEY" \ -H "Content-Type: application/json" \ -d '' ``` The strict create schema also accepts `progress`, `team_id`, `lead_user_id`, `template_id`, `deal_id`, `company_id`, `github_url`, `external_id`, and `hosted`. It rejects unknown fields such as `target_date`. ## Project tasks | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/api/v1/issues` | List tasks or support tickets | | `POST` | `/api/v1/issues` | Create a task or ticket | | `GET` | `/api/v1/issues/` | Read one item | | `PATCH` | `/api/v1/issues/` | Update one item | | `DELETE` | `/api/v1/issues/` | Soft-delete a project task only | Create a task: ```bash curl -X POST https://platform.workestra.app/api/v1/issues \ -H "Authorization: Bearer $WORKESTRA_API_KEY" \ -H "Content-Type: application/json" \ -d '' ``` `kind` is required and must be `task` or `ticket`. The strict create schema also accepts `status`, `assignee_id`, `parent_id`, `cycle_id`, and `estimate_hours`; it does not accept a `labels` array. > **Warning:** Omitting `kind` from `GET /api/v1/issues` currently defaults the data source to project tasks. Use `kind=task` explicitly in integrations. The DELETE implementation only deletes project tasks and must not be used for support tickets. ## List filters and pagination Projects support `page` and `limit`. Issues support: - `page` and `limit` - `project_id` - `status` - `kind` - `search` Parameters such as `per_page`, `sort`, `order`, `overdue`, and list-level `assignee_id` are not implemented. Successful `/api/v1` calls use the common response envelope: ```json } ``` ## Related documentation - [Projects endpoint reference](/docs/api/endpoints/projects) - [Issues endpoint reference](/docs/api/endpoints/issues) - [API status matrix](/docs/api/status) - [Projects webhooks](/docs/modules/projects/integrations/webhooks) # Projects AI and MCP Tools Source: https://docs.workestra.app/docs/modules/projects/integrations/ai-chat The 14 Projects tools available through Workestra AI and MCP. The shared Workestra tool registry currently exposes 14 Projects tools. | Tool | Mode | Purpose | | --- | --- | --- | | `list_projects` | Read | List projects, optionally by status | | `get_project` | Read | Get one project | | `list_tasks` | Read | Filter tasks by project, status, priority, or assignee | | `list_my_tasks` | Read | List up to 50 tasks assigned to the current actor | | `get_project_health` | Read | Compute schedule/completion health and task counts | | `create_project` | Write | Create a project | | `create_task` | Write | Create a project task | | `update_task` | Write | Update task fields | | `assign_task` | Write | Assign, unassign, or reassign a task | | `add_comment` | Write | Add a comment to a project task | | `start_cycle` | Write | Move a planned cycle to active | | `complete_cycle` | Write | Move an active cycle to completed | | `archive_task` | Write | Soft-delete a task | | `delete_task` | Write | Soft-delete alias of `archive_task` | `delete_task` is not a permanent delete; it sets `deleted_at`, like `archive_task`. ## In-app AI Open the AI panel and ask in plain language, for example: - "List my open tasks in Website Redesign." - "Create a high-priority task due Friday." - "Show project health for Website Redesign." - "Start the planned July cycle." Read tools run immediately. In-app write tools show a confirmation step and execute with the signed-in user's permissions. ## External MCP The same registry is available to MCP clients, but the execution experience differs: - the API key and MCP permission policy determine which tools are visible; - `--read-only` hides write tools locally; - permitted MCP writes execute without the Workestra in-app confirmation card. Use `GET /api/mcp/tools/list?features=projects&includeDenied=true&includeSchemas=true` to retrieve the exact schemas and permission result for a test key. See [MCP Tool Discovery](/docs/integrations/mcp/tools). ## Related documentation - [Projects REST API](/docs/modules/projects/integrations/rest-api) - [Tasks](/docs/modules/projects/tasks) - [Cycles](/docs/modules/projects/cycles) # Project Webhooks Source: https://docs.workestra.app/docs/modules/projects/integrations/webhooks Current signed-delivery and event behavior for Projects webhooks. Projects webhooks use the shared Workestra delivery engine and may be workspace-wide or scoped to one project. > **Warning:** Delivery is asynchronous and can take up to 24 hours on the current service tier. Use a test delivery to validate the receiver immediately. ## Configure Use the Projects webhook settings to provide: - an HTTPS URL; - one or more event names; - an optional project scope; - an enabled state; - a secret of at least 16 characters, or an auto-generated secret. The current settings action recognizes the following intended event names: - `issue.created` - `issue.updated` - `issue.status_changed` - `issue.assignee_changed` - `issue.deleted` - `comment.added` - `project.updated` - `webhook.test` > **Warning:** Some event names retain compatibility aliases. Treat the name shown in test payloads and delivery history as authoritative, and make receivers tolerant of documented aliases. ## Signed request Every attempt includes: ```text X-Workestra-Signature: sha256= X-Workestra-Timestamp: X-Workestra-Event: X-Workestra-Delivery-Id: X-Workestra-Module: projects ``` Compute HMAC-SHA256 over: ```text . ``` using the webhook secret. Compare the `sha256=` value in constant time, reject stale timestamps, and deduplicate using the delivery ID. The [Support webhook guide](/docs/modules/support/webhooks) includes a Node.js verifier for this shared signature contract. ## Delivery behavior - `2xx` marks the delivery successful. - `429`, `5xx`, network errors, and the 10-second timeout are retryable. - Other `4xx` responses are permanent failures. - The engine allows four attempts total and records retry due times at 1, 5, and 30 minutes. - With a daily worker, a retryable row may wait until the next daily drain even after its due time. ## Test checklist 1. Use a disposable project and webhook. 2. Send `webhook.test` and verify headers/signature. 3. Subscribe to the exact emitted event string for the write path under test. 4. confirm a queue/delivery row appears. 5. return `2xx` promptly. 6. confirm duplicate delivery IDs are handled safely. ## Related documentation - [Projects REST API](/docs/modules/projects/integrations/rest-api) - [General webhook contract](/docs/api/webhooks) - [Projects AI and MCP Tools](/docs/modules/projects/integrations/ai-chat) # AI Tools (Finance) Source: https://docs.workestra.app/docs/modules/finance/ai-tools The 27 finance tools exposed to Workestra AI and MCP. Workestra currently registers 27 finance tools across invoicing, expenses, banking, payments, credit notes, and PEPPOL. These definitions come from the shared `@workestra/tools` registry used by the in-app assistant and MCP. > **Info:** In the Workestra AI panel, write tools show a confirmation step. External MCP clients do not receive that Workestra UI confirmation card: a permitted tool call executes immediately, subject to the API key's scopes and MCP policy. ## Invoicing (9) | Tool | Mode | Purpose | | --- | --- | --- | | `list_invoices` | Read | Filter invoices by status, customer, amount, or overdue state | | `get_invoice` | Read | Get an invoice with contact, company, and line items | | `create_invoice` | Write | Create an invoice | | `get_invoice_stats` | Read | Summarize paid, pending, and overdue invoices | | `list_products` | Read | Search finance products | | `get_product` | Read | Get one finance product | | `convert_quotation_to_invoice` | Write | Idempotently convert an accepted quotation | | `bill_time_entries_to_invoice` | Write | Append billable time to a draft invoice or create one | | `delete_invoice` | Write | Permanently delete an unpaid invoice and its line items | `delete_invoice` refuses paid invoices. `bill_time_entries_to_invoice` marks selected time entries as billed so a retry cannot bill them twice. ## Expenses (5) | Tool | Mode | Purpose | | --- | --- | --- | | `list_expenses` | Read | Filter expenses | | `create_expense` | Write | Submit an expense | | `update_expense` | Write | Edit mutable fields | | `approve_expense` | Write | Approve or reject a pending expense | | `delete_expense` | Write | Permanently delete a non-approved expense | ## Banking (3) | Tool | Mode | Purpose | | --- | --- | --- | | `list_bank_accounts` | Read | List connected bank accounts | | `list_bank_transactions` | Read | Filter bank transactions | | `sync_bank_account` | Read | Return sync state, provider, cursor, and last-sync time | Despite its name, `sync_bank_account` does not initiate a provider sync. Use the Finance UI sync action or the server-side banking route to force a refresh. ## Payments (3) | Tool | Mode | Purpose | | --- | --- | --- | | `list_invoice_payments` | Read | List recorded invoice payments | | `create_payment_checkout` | Write | Create a Stripe-hosted checkout session | | `refund_payment` | Write | Issue a full or partial provider refund | > **Warning:** A checkout URL is only usable when Stripe and the workspace's payment readiness requirements are configured. Review [Payments](/docs/modules/finance/payments) before sending a generated URL to a customer. ## Credit notes (4) | Tool | Mode | Purpose | | --- | --- | --- | | `list_credit_notes` | Read | Filter credit notes | | `create_credit_note` | Write | Create a credit note | | `apply_credit_note` | Write | Apply all or part of a credit note to an invoice | | `delete_credit_note` | Write | Permanently delete an unapplied credit note | Applied credit notes cannot be deleted through the tool. ## PEPPOL (3) | Tool | Mode | Purpose | | --- | --- | --- | | `send_peppol_invoice` | Write | Queue a PEPPOL submission intent | | `list_peppol_inbox` | Read | List inbound PEPPOL messages | | `get_peppol_inbound` | Read | Read one inbound PEPPOL message | `send_peppol_invoice` queues the submission and marks it pending; server-side routes perform provider dispatch. ## Test through MCP 1. Create an API key with the relevant finance permissions. 2. Connect an MCP client using [MCP setup](/docs/integrations/mcp). 3. Call `tools/list` and confirm the expected finance tools are allowed. 4. Test reads first. 5. Use a disposable workspace for destructive tools such as invoice, expense, or credit-note deletion. Live tool discovery and permission behavior are documented in [MCP Tool Catalog](/docs/integrations/mcp/tools). ## Surface differences | Surface | Contract | | --- | --- | | In-app AI | Shared tool registry plus Workestra confirmation UI for writes | | MCP | Shared tool registry; permitted calls execute through the MCP tool-call endpoint | | REST API | HTTP resources and schemas; not a one-to-one mirror of tool names | Do not assume a tool name is also a REST endpoint.