{"openapi":"3.1.0","info":{"title":"MavenOS API","version":"2026-10-21","summary":"Read and change Work from your own software.","description":"The MavenOS API lets a script or another system read and change tasks and projects, and add or update sales companies, contacts and deals, in one workspace, as the person or service the key belongs to.\n\nSend `Authorization: Bearer mos_<prefix>_<secret>`. Every POST and PATCH needs an `Idempotency-Key` uuid. Bodies are JSON, at most 64 KB (32 KB on the Sales calls). There are no deletes, and nothing about HR is ever returned. Money is returned only as deal amounts (`one_time_cents`, `monthly_cents`), and only to a key that acts as an owner, admin or finance person.\n\nPer-key limits by rate class: basic: 60 reads and 20 writes a minute, 300 writes a day; standard: 120 reads and 30 writes a minute, 2000 writes a day; scale: 300 reads and 60 writes a minute, 10000 writes a day. Hard caps, no overage. A day is the UTC calendar day: the daily write count starts again at 00:00 UTC, and the 80 and 100 percent notices follow the same day. The per-minute limits are a rolling minute. A 429 for the daily cap sets Retry-After to the seconds left until 00:00 UTC.\n\nWrites need the API access add-on and a key with the `work:write` scope (or `crm:write` for the sales calls, which read with `crm:read`). Workspaces that require two-step sign-in refuse API keys. Browsers cannot call the API directly (no CORS); call it from a server."},"servers":[{"url":"/","description":"The same address as the app."}],"tags":[{"name":"Workspace"},{"name":"Tasks"},{"name":"Projects"},{"name":"People"},{"name":"Sales"}],"security":[{"bearerAuth":[]}],"paths":{"/api/v2/{org}/me":{"get":{"operationId":"getMe","tags":["Workspace"],"summary":"Show this key","description":"Returns the key's name, scopes, expiry, the person it acts as, the workspace, which tools are on, the rate limits that apply, and whether a write would be accepted right now (`can_write`). A good first call to test a key.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"The record.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Me"}}},"example":{"data":{"key":{"id":"c9d0e1f2-a3b4-4c5d-9e6f-7a8b9c0d1ec5","name":"Reporting script","prefix":"k3x9q2ab","kind":"service","scopes":["work:read","work:write"],"expires_at":"2027-01-18T00:00:00.000000Z","rate_class":"basic"},"person":{"user_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","role":"member","name":"API: Reporting script","is_service":true},"org":{"slug":"acme"},"can_write":true,"modules":{"work":true,"people":true,"api":true},"limits":{"read_per_minute":60,"write_per_minute":20,"write_per_day":300}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/tasks":{"get":{"operationId":"listTasks","tags":["Tasks"],"summary":"List tasks","description":"Tasks the key's person can see, newest change first. Private tasks appear only when that person created them, is assigned, or is an owner or admin.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/StatusTask"},{"$ref":"#/components/parameters/ProjectIdFilter"},{"$ref":"#/components/parameters/AssigneeId"},{"$ref":"#/components/parameters/UpdatedSince"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Task"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","project_id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","phase_id":null,"title":"Send the signed contract","description":"Use the template from last quarter.","status":"open","priority":"medium","due_on":"2026-11-03","completed_at":null,"created_by":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","visibility":"public","client_id":null,"team_id":null,"assignee_ids":["e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a81"],"created_at":"2026-10-20T14:03:11.482913Z","updated_at":"2026-10-20T15:41:02.118204Z"}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}},"post":{"operationId":"createTask","tags":["Tasks"],"summary":"Create a task","description":"Creates one task as the key's person. It is public to the workspace unless `visibility` is `private`. Assigning people notifies them.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskBody"},"example":{"title":"Send the signed contract","project_id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","priority":"medium","due_on":"2026-11-03","assignee_ids":["e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a81"]}}}},"responses":{"201":{"description":"Created. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"},"Location":{"$ref":"#/components/headers/Location"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/tasks/{id}":{"get":{"operationId":"getTask","tags":["Tasks"],"summary":"Get a task","description":"One task. A task the person cannot see answers 404, the same as one that does not exist.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"The record.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Task"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","project_id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","phase_id":null,"title":"Send the signed contract","description":"Use the template from last quarter.","status":"open","priority":"medium","due_on":"2026-11-03","completed_at":null,"created_by":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","visibility":"public","client_id":null,"team_id":null,"assignee_ids":["e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a81"],"created_at":"2026-10-20T14:03:11.482913Z","updated_at":"2026-10-20T15:41:02.118204Z"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}},"patch":{"operationId":"updateTask","tags":["Tasks"],"summary":"Change a task's fields","description":"Overwrites only the fields you send. Send null for `description`, `due_on` or `estimate_minutes` to clear it. It does not change status, assignees or who can see the task; use the status and assignees calls for those.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaskBody"},"example":{"priority":"high","due_on":null}}}},"responses":{"200":{"description":"Done. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/tasks/{id}/comments":{"get":{"operationId":"listTaskComments","tags":["Tasks"],"summary":"List a task's comments","description":"Comments on one task, oldest first.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9ca3","task_id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","author_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","body":"Sent to legal for a last look.","created_at":"2026-10-20T15:00:00.000000Z","edited_at":null}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}},"post":{"operationId":"addTaskComment","tags":["Tasks"],"summary":"Add a comment to a task","description":"Adds one comment, written as the key's person. A comment cannot be edited or deleted through the API.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTaskCommentBody"},"example":{"body":"Sent to legal for a last look."}}}},"responses":{"201":{"description":"Created. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/tasks/{id}/status":{"post":{"operationId":"setTaskStatus","tags":["Tasks"],"summary":"Set a task's status","description":"Sets the status. Sending the status it already has changes nothing.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetTaskStatusBody"},"example":{"status":"done"}}}},"responses":{"200":{"description":"Done. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/tasks/{id}/assignees":{"post":{"operationId":"assignTask","tags":["Tasks"],"summary":"Add an assignee","description":"Adds one workspace member as an assignee and notifies them. It never removes anyone.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignTaskBody"},"example":{"user_id":"e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a81"}}}},"responses":{"200":{"description":"Done. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/projects":{"get":{"operationId":"listProjects","tags":["Projects"],"summary":"List projects","description":"Projects the key's person can see, newest change first.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/StatusProject"},{"$ref":"#/components/parameters/ClientId"},{"$ref":"#/components/parameters/UpdatedSince"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","name":"Spring launch","status":"active","client_id":"f6a7b8c9-d0e1-4f2a-8b3c-4d5e6f7a8b92","start_date":"2026-11-01","end_date":"2027-03-31","created_by":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","created_at":"2026-10-01T09:00:00.000000Z","updated_at":"2026-10-19T17:22:45.903115Z"}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}},"post":{"operationId":"createProject","tags":["Projects"],"summary":"Create a project","description":"Creates one project as the key's person. It adds no phases or tasks.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectBody"},"example":{"name":"Spring launch","client_id":"f6a7b8c9-d0e1-4f2a-8b3c-4d5e6f7a8b92","start_date":"2026-11-01","end_date":"2027-03-31"}}}},"responses":{"201":{"description":"Created. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"},"Location":{"$ref":"#/components/headers/Location"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/projects/{id}":{"get":{"operationId":"getProject","tags":["Projects"],"summary":"Get a project","description":"One project.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"The record.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Project"}}},"example":{"data":{"id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","name":"Spring launch","status":"active","client_id":"f6a7b8c9-d0e1-4f2a-8b3c-4d5e6f7a8b92","start_date":"2026-11-01","end_date":"2027-03-31","created_by":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","created_at":"2026-10-01T09:00:00.000000Z","updated_at":"2026-10-19T17:22:45.903115Z"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}},"patch":{"operationId":"updateProject","tags":["Projects"],"summary":"Change a project's fields","description":"Overwrites only the fields you send. Send null for `client_id`, `start_date` or `end_date` to clear it.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectBody"},"example":{"status":"on_hold"}}}},"responses":{"200":{"description":"Done. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/projects/{id}/notes":{"get":{"operationId":"listProjectNotes","tags":["Projects"],"summary":"List a project's notes","description":"Notes on one project, newest first. Notes about a task the person may not read are left out.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Note"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"b8c9d0e1-f2a3-4b4c-8d5e-6f7a8b9c0db4","project_id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","phase_id":null,"task_id":null,"author_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","body":"Kickoff call moved to Thursday.","pinned":false,"created_at":"2026-10-20T16:10:00.000000Z","edited_at":null}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}},"post":{"operationId":"addProjectNote","tags":["Projects"],"summary":"Add a note to a project","description":"Adds one note, written as the key's person, optionally tied to a task or phase of that project and pinned. A note cannot be edited or deleted through the API.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:write","requestBody":{"required":true,"description":"JSON, at most 64 KB. Fields not listed here are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddProjectNoteBody"},"example":{"body":"Kickoff call moved to Thursday.","pinned":false}}}},"responses":{"201":{"description":"Created. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WriteItem"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/ReadOnly"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMedia"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/stages":{"get":{"operationId":"listCrmStages","tags":["Sales"],"summary":"List deal stages","description":"The workspace's pipeline stages in board order, including archived ones, so you can see which stage keys exist. Needs a key with the `crm:read` scope. The key's person must be able to read Sales.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Stage"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"key":"qualified","label":"Qualified","position":1,"kind":"open"}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/companies":{"get":{"operationId":"listCrmCompanies","tags":["Sales"],"summary":"List companies","description":"The workspace's companies, oldest change first, so a sync can run forward and never miss one: pass `updated_since` (the `updated_at` of the last record you saved; it is inclusive, so one record can repeat) and `after` (the `next_cursor` of the previous page). `updated_since` must be a real moment between 2000 and tomorrow. Needs a key with the `crm:read` scope; the key's person must be able to read Sales. `external_id` is the id your own integration sent when it created the company, or null. Companies carry no money.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/UpdatedSince"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Company"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","external_id":"crm-1042","name":"Northwind Dental","status":"active","crm_status":"prospect","contact_email":"office@northwind.example","website":"https://northwind.example","created_at":"2026-10-12T14:03:11.482913Z","updated_at":"2026-10-20T15:41:02.118204Z"}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/companies/{id}":{"get":{"operationId":"getCrmCompany","tags":["Sales"],"summary":"Get a company","description":"One company, with the same fields as the list. A company the key's person cannot read answers 404, the same as one that does not exist.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/CompanyId"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"The record.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Company"}}},"example":{"data":{"id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","external_id":"crm-1042","name":"Northwind Dental","status":"active","crm_status":"prospect","contact_email":"office@northwind.example","website":"https://northwind.example","created_at":"2026-10-12T14:03:11.482913Z","updated_at":"2026-10-20T15:41:02.118204Z"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/contacts":{"get":{"operationId":"listCrmContacts","tags":["Sales"],"summary":"List contacts","description":"The workspace's contacts, oldest change first, paged and filtered the same way as the company list (`company_id` keeps one company's contacts). The email address is included because the contact upsert matches on it; phone numbers, notes and addresses are never returned. Contacts carry no money.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/CompanyIdFilter"},{"$ref":"#/components/parameters/UpdatedSince"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"2f3a4b5c-6d7e-4f8a-9b9c-0d1e2f3a4b52","external_id":"lead-88231","first_name":"Dana","last_name":"Whitfield","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","email":"dana@northwind.example","status":"active","role":"Office manager","is_primary":true,"created_at":"2026-10-12T14:05:40.000000Z","updated_at":"2026-10-20T15:41:02.118204Z"}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/contacts/{id}":{"get":{"operationId":"getCrmContact","tags":["Sales"],"summary":"Get a contact","description":"One contact, with the same fields as the list. A contact the key's person cannot read answers 404.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/ContactId"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"The record.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Contact"}}},"example":{"data":{"id":"2f3a4b5c-6d7e-4f8a-9b9c-0d1e2f3a4b52","external_id":"lead-88231","first_name":"Dana","last_name":"Whitfield","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","email":"dana@northwind.example","status":"active","role":"Office manager","is_primary":true,"created_at":"2026-10-12T14:05:40.000000Z","updated_at":"2026-10-20T15:41:02.118204Z"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/deals":{"get":{"operationId":"listCrmDeals","tags":["Sales"],"summary":"List deals","description":"The deals the key's person can see (a member limited to their own deals sees only those), oldest change first, paged and filtered like the company list; `stage` keeps one stage key from GET /crm/stages. `one_time_cents` and `monthly_cents` are present only when the key acts as an owner, admin or finance person; for anyone else the two fields are left out of every deal, not set to zero. Owner and agent names are never returned.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/CompanyIdFilter"},{"$ref":"#/components/parameters/DealStageFilter"},{"$ref":"#/components/parameters/UpdatedSince"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Deal"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","external_id":"deal-5531","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"qualified","priority":"medium","deal_type":"new_business","expected_close_on":"2026-12-15","one_time_cents":450000,"monthly_cents":15000,"created_at":"2026-10-12T14:10:00.000000Z","updated_at":"2026-10-20T15:41:02.118204Z"}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/deals/{id}":{"get":{"operationId":"getCrmDeal","tags":["Sales"],"summary":"Get a deal","description":"One deal, with the same fields and the same money rule as the list. A deal the key's person cannot see answers 404.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/DealId"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"The record.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Deal"}}},"example":{"data":{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","external_id":"deal-5531","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"qualified","priority":"medium","deal_type":"new_business","expected_close_on":"2026-12-15","one_time_cents":450000,"monthly_cents":15000,"created_at":"2026-10-12T14:10:00.000000Z","updated_at":"2026-10-20T15:41:02.118204Z"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/companies/upsert":{"post":{"operationId":"upsertCompany","tags":["Sales"],"summary":"Create or update a company","description":"Finds the company by your `external_id`, then by exact name (not case sensitive), and creates it when none matches. `on_match` says what a match does: `update` (the default) overwrites the fields you send, `fill_blanks` only fills fields that are empty, `skip` changes nothing. The answer is 201 with `match: created` for a new company and 200 with `match: updated` or `unchanged` otherwise. If two or more companies match, nothing is changed and the answer is 409 `ambiguous_match`: send the `external_id` of the one you mean. Needs the `crm:write` scope and the API access add-on. Deals and their money are separate calls.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:write","requestBody":{"required":true,"description":"JSON, at most 32 KB. Fields not listed here are refused. A key may not appear twice in one object, and JSON may nest at most 8 levels.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyUpsertBody"},"example":{"external_id":"crm-1042","name":"Northwind Dental","website":"https://northwind.example","business_type":"Dental practice","importance":3,"crm_status":"prospect","on_match":"fill_blanks"}}}},"responses":{"200":{"description":"A record matched (`match: updated` or `unchanged`). A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/UpsertResult"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","name":"Northwind Dental","external_id":"crm-1042","match":"created"}}}}},"201":{"description":"Created: no record matched, so a new one was made (`match: created`). A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/UpsertResult"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","name":"Northwind Dental","external_id":"crm-1042","match":"created"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLargeCrm"},"415":{"$ref":"#/components/responses/UnsupportedMediaCrm"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/contacts/upsert":{"post":{"operationId":"upsertContact","tags":["Sales"],"summary":"Create or update a contact","description":"Finds the contact by your `external_id`, then by email (not case sensitive), and creates it when none matches. Send an `external_id` or an `email`, or both. Link the contact to a company with `company_id` or with `company_external_id` (the `external_id` you gave when you upserted the company), not both. `on_match` works as for companies. The answer is 201 with `match: created` for a new contact and 200 with `match: updated` or `unchanged` otherwise. If two or more contacts match, nothing is changed and the answer is 409 `ambiguous_match`. Do Not Email and Do Not Call are never changed through the API. Needs the `crm:write` scope and the API access add-on. Deals and their money are separate calls.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:write","requestBody":{"required":true,"description":"JSON, at most 32 KB. Fields not listed here are refused. A key may not appear twice in one object, and JSON may nest at most 8 levels.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpsertBody"},"example":{"external_id":"lead-88231","first_name":"Dana","last_name":"Whitfield","email":"dana@northwind.example","company_external_id":"crm-1042","role":"decision_maker","lead_source":"website_funnel_page","on_match":"update"}}}},"responses":{"200":{"description":"A record matched (`match: updated` or `unchanged`). A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/UpsertResult"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"2f3a4b5c-6d7e-4f8a-9b9c-0d1e2f3a4b52","first_name":"Dana","last_name":"Whitfield","email":"dana@northwind.example","external_id":"lead-88231","match":"updated"}}}}},"201":{"description":"Created: no record matched, so a new one was made (`match: created`). A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/UpsertResult"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"2f3a4b5c-6d7e-4f8a-9b9c-0d1e2f3a4b52","first_name":"Dana","last_name":"Whitfield","email":"dana@northwind.example","external_id":"lead-88231","match":"updated"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLargeCrm"},"415":{"$ref":"#/components/responses/UnsupportedMediaCrm"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/deals/upsert":{"post":{"operationId":"upsertDeal","tags":["Sales"],"summary":"Create or update a deal","description":"Finds the deal by your `external_id` (required; a deal is never matched by name) and creates it when none matches. `name` and `stage` are used only when the deal is created: for a deal that already exists they are ignored, so use the stage call to move it. Link the deal to a company with `company_id` or with `company_external_id` (the `external_id` you gave the company), not both. `on_match` works as for companies. The answer is 201 with `match: created` for a new deal and 200 with `match: updated` or `unchanged` otherwise. Money: `one_time_cents` and `monthly_cents` are whole cents (integers from 0 to 1000000000000). Sending either needs a key that acts as an owner, admin or finance person; for anyone else the answer is 403 `money_not_allowed` and nothing is changed. For those people the amounts are also left out of the deal in the answer. Won, lost and not applicable go through the stage call. Needs the `crm:write` scope and the API access add-on.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:write","requestBody":{"required":true,"description":"JSON, at most 32 KB. Fields not listed here are refused. A key may not appear twice in one object, and JSON may nest at most 8 levels.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealUpsertBody"},"example":{"external_id":"deal-5531","name":"Northwind Dental: new website","company_external_id":"crm-1042","deal_type":"new_business","stage":"qualified","one_time_cents":450000,"monthly_cents":15000,"expected_close_on":"2026-12-15","on_match":"update"}}}},"responses":{"200":{"description":"A record matched (`match: updated` or `unchanged`). A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/DealUpsertResult"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"qualified","priority":"medium","owner_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","sales_agent_id":null,"expected_close_on":"2026-12-15","path":"/crm/deals/3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","one_time_cents":450000,"monthly_cents":15000,"match":"created","external_id":"deal-5531"}}}}},"201":{"description":"Created: no record matched, so a new one was made (`match: created`). A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/DealUpsertResult"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"qualified","priority":"medium","owner_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","sales_agent_id":null,"expected_close_on":"2026-12-15","path":"/crm/deals/3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","one_time_cents":450000,"monthly_cents":15000,"match":"created","external_id":"deal-5531"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLargeCrm"},"415":{"$ref":"#/components/responses/UnsupportedMediaCrm"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/crm/deals/stage":{"post":{"operationId":"moveDealStage","tags":["Sales"],"summary":"Move a deal to a stage","description":"Moves one deal, named by its `deal_id` or by your `external_id` (send exactly one of them), to the stage with the key you give. Moving between open stages works for anyone who can write in Sales. Moving a deal to won, lost or not applicable, or reopening a closed deal, needs a key that acts as an owner or admin; for anyone else the answer is 403 `forbidden`. Moving to lost needs a `reason` (up to 500 characters). The answer is 200 with the deal as it now stands. A deal already in that stage is left as it is. A deal that does not exist, or belongs to another workspace, answers 404. Needs the `crm:write` scope and the API access add-on.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"crm:write","requestBody":{"required":true,"description":"JSON, at most 32 KB. Fields not listed here are refused. A key may not appear twice in one object, and JSON may nest at most 8 levels.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealStageBody"},"example":{"external_id":"deal-5531","stage":"lost","reason":"Chose another vendor."}}}},"responses":{"200":{"description":"Done. A repeated Idempotency-Key answers the same status with the first answer and an `Idempotent-Replayed: true` header; nothing is written again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/DealStageResult"},"notice":{"$ref":"#/components/schemas/Notice"}}},"example":{"data":{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"proposal","priority":"medium","owner_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","sales_agent_id":null,"expected_close_on":"2026-12-15","path":"/crm/deals/3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","external_id":"deal-5531"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLargeCrm"},"415":{"$ref":"#/components/responses/UnsupportedMediaCrm"},"422":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v2/{org}/people":{"get":{"operationId":"listPeople","tags":["People"],"summary":"List people","description":"Workspace members by name and role, so you can pick an assignee. `name` is the full name; `first_name` and `last_name` are the same name in two parts, `null` when a person has no split yet. Nothing else about a person is shown.","parameters":[{"$ref":"#/components/parameters/Org"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/Version"}],"security":[{"bearerAuth":[]}],"x-required-scope":"work:read","responses":{"200":{"headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"description":"A page of items.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Person"}},"next_cursor":{"type":["string","null"],"description":"Pass as `after` for the next page. Null on the last page."}}},"example":{"data":[{"id":"e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a81","name":"Priya Raman","first_name":"Priya","last_name":"Raman","role":"member"}],"next_cursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/InvalidKey"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/Internal"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"mos_<prefix>_<secret>","description":"An API key made in Settings, API access. Shown once when made."}},"schemas":{"Task":{"type":"object","required":["id","project_id","phase_id","title","description","status","priority","due_on","completed_at","created_by","visibility","client_id","team_id","assignee_ids","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"The task id."},"project_id":{"type":["string","null"],"format":"uuid","description":"The project it belongs to."},"phase_id":{"type":["string","null"],"format":"uuid","description":"The phase it belongs to."},"title":{"type":"string","maxLength":200},"description":{"type":["string","null"],"maxLength":4000},"status":{"type":"string","enum":["open","in_progress","done","cancelled"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"due_on":{"type":["string","null"],"format":"date"},"completed_at":{"type":["string","null"],"format":"date-time","description":"When it was completed. A UTC timestamp with microseconds."},"created_by":{"type":["string","null"],"format":"uuid","description":"The person who created it."},"visibility":{"type":"string","enum":["public","private"]},"client_id":{"type":["string","null"],"format":"uuid","description":"The client it is for."},"team_id":{"type":["string","null"],"format":"uuid","description":"The team it is for."},"assignee_ids":{"type":"array","items":{"type":"string","format":"uuid","description":"A person id."},"description":"Everyone assigned."},"created_at":{"type":"string","format":"date-time","description":"When it was created. A UTC timestamp with microseconds."},"updated_at":{"type":"string","format":"date-time","description":"When it last changed. A UTC timestamp with microseconds."}},"additionalProperties":false,"example":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","project_id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","phase_id":null,"title":"Send the signed contract","description":"Use the template from last quarter.","status":"open","priority":"medium","due_on":"2026-11-03","completed_at":null,"created_by":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","visibility":"public","client_id":null,"team_id":null,"assignee_ids":["e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a81"],"created_at":"2026-10-20T14:03:11.482913Z","updated_at":"2026-10-20T15:41:02.118204Z"}},"Project":{"type":"object","required":["id","name","status","client_id","start_date","end_date","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"The project id."},"name":{"type":"string","maxLength":120},"status":{"type":"string","enum":["planning","active","on_hold","complete"]},"client_id":{"type":["string","null"],"format":"uuid","description":"The client it is for."},"start_date":{"type":["string","null"],"format":"date"},"end_date":{"type":["string","null"],"format":"date"},"created_by":{"type":["string","null"],"format":"uuid","description":"The person who created it."},"created_at":{"type":"string","format":"date-time","description":"When it was created. A UTC timestamp with microseconds."},"updated_at":{"type":"string","format":"date-time","description":"When it last changed. A UTC timestamp with microseconds."}},"additionalProperties":false,"example":{"id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","name":"Spring launch","status":"active","client_id":"f6a7b8c9-d0e1-4f2a-8b3c-4d5e6f7a8b92","start_date":"2026-11-01","end_date":"2027-03-31","created_by":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","created_at":"2026-10-01T09:00:00.000000Z","updated_at":"2026-10-19T17:22:45.903115Z"}},"Comment":{"type":"object","required":["id","task_id","author_id","body","created_at","edited_at"],"properties":{"id":{"type":"string","format":"uuid","description":"The comment id."},"task_id":{"type":"string","format":"uuid","description":"The task it is on."},"author_id":{"type":["string","null"],"format":"uuid","description":"The person who wrote it."},"body":{"type":"string","maxLength":4000},"created_at":{"type":"string","format":"date-time","description":"When it was written. A UTC timestamp with microseconds."},"edited_at":{"type":["string","null"],"format":"date-time","description":"When it was last edited. A UTC timestamp with microseconds."}},"additionalProperties":false,"example":{"id":"a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9ca3","task_id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","author_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","body":"Sent to legal for a last look.","created_at":"2026-10-20T15:00:00.000000Z","edited_at":null}},"Note":{"type":"object","required":["id","project_id","phase_id","task_id","author_id","body","pinned","created_at","edited_at"],"properties":{"id":{"type":"string","format":"uuid","description":"The note id."},"project_id":{"type":"string","format":"uuid","description":"The project it is on."},"phase_id":{"type":["string","null"],"format":"uuid","description":"The phase it is tied to."},"task_id":{"type":["string","null"],"format":"uuid","description":"The task it is tied to."},"author_id":{"type":["string","null"],"format":"uuid","description":"The person who wrote it."},"body":{"type":"string","maxLength":10000},"pinned":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","description":"When it was written. A UTC timestamp with microseconds."},"edited_at":{"type":["string","null"],"format":"date-time","description":"When it was last edited. A UTC timestamp with microseconds."}},"additionalProperties":false,"example":{"id":"b8c9d0e1-f2a3-4b4c-8d5e-6f7a8b9c0db4","project_id":"b1f0e2d3-4c5b-4a69-8788-9a0b1c2d3e4f","phase_id":null,"task_id":null,"author_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","body":"Kickoff call moved to Thursday.","pinned":false,"created_at":"2026-10-20T16:10:00.000000Z","edited_at":null}},"Stage":{"type":"object","required":["key","label","position","kind"],"additionalProperties":true,"description":"One pipeline stage. Use `key` to refer to a stage.","properties":{"key":{"type":"string","description":"The stable stage key, lower case letters, digits and underscores."},"label":{"type":"string","maxLength":60,"description":"The name shown on the board."},"position":{"type":"integer","minimum":0,"description":"Board order, lowest first."},"kind":{"type":"string","enum":["open","won","lost","closed_other"],"description":"Whether the stage is open or ends a deal."}},"example":{"key":"qualified","label":"Qualified","position":1,"kind":"open"}},"Company":{"type":"object","required":["id","external_id","name","status","crm_status","created_at","updated_at"],"additionalProperties":false,"description":"One company. No money, owner, phone, address or notes.","properties":{"id":{"type":"string","format":"uuid","description":"The company id."},"external_id":{"type":["string","null"],"description":"The id your own integration sent when it created the company, or null."},"name":{"type":"string"},"status":{"type":"string","enum":["active","archived"]},"crm_status":{"type":"string","enum":["prospect","active","not_active","blacklisted"]},"contact_email":{"type":["string","null"],"description":"The company's general email address."},"website":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","description":"When it was created. A UTC timestamp with microseconds."},"updated_at":{"type":"string","format":"date-time","description":"When it last changed. Use it with `updated_since`. A UTC timestamp with microseconds."}},"example":{"id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","external_id":"crm-1042","name":"Northwind Dental","status":"active","crm_status":"prospect","contact_email":"office@northwind.example","website":"https://northwind.example","created_at":"2026-10-12T14:03:11.482913Z","updated_at":"2026-10-20T15:41:02.118204Z"}},"Contact":{"type":"object","required":["id","external_id","first_name","last_name","company_id","status","is_primary","created_at","updated_at"],"additionalProperties":false,"description":"One contact. The email is included; the phone, notes and address are not. No money.","properties":{"id":{"type":"string","format":"uuid","description":"The contact id."},"external_id":{"type":["string","null"],"description":"The id your own integration sent when it created the contact, or null."},"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"company_id":{"type":["string","null"],"format":"uuid","description":"The company the contact belongs to."},"email":{"type":["string","null"]},"status":{"type":"string"},"role":{"type":["string","null"],"description":"The contact's role at the company."},"is_primary":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","description":"When it was created. A UTC timestamp with microseconds."},"updated_at":{"type":"string","format":"date-time","description":"When it last changed. Use it with `updated_since`. A UTC timestamp with microseconds."}},"example":{"id":"2f3a4b5c-6d7e-4f8a-9b9c-0d1e2f3a4b52","external_id":"lead-88231","first_name":"Dana","last_name":"Whitfield","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","email":"dana@northwind.example","status":"active","role":"Office manager","is_primary":true,"created_at":"2026-10-12T14:05:40.000000Z","updated_at":"2026-10-20T15:41:02.118204Z"}},"Deal":{"type":"object","required":["id","external_id","name","company_id","stage","created_at","updated_at"],"additionalProperties":false,"description":"One deal. `one_time_cents` and `monthly_cents` are present only when the key acts as an owner, admin or finance person; for anyone else they are left out. No owner or agent names.","properties":{"id":{"type":"string","format":"uuid","description":"The deal id."},"external_id":{"type":["string","null"],"description":"The id your own integration sent when it created the deal, or null."},"name":{"type":"string"},"company_id":{"type":["string","null"],"format":"uuid","description":"The company the deal is with."},"stage":{"type":"string","description":"A stage key from GET /crm/stages."},"priority":{"type":["string","null"]},"deal_type":{"type":["string","null"]},"expected_close_on":{"type":["string","null"],"format":"date"},"one_time_cents":{"type":"integer","minimum":0,"description":"The one-time amount in cents. Present only for an owner, admin or finance key."},"monthly_cents":{"type":"integer","minimum":0,"description":"The monthly amount in cents. Present only for an owner, admin or finance key."},"created_at":{"type":"string","format":"date-time","description":"When it was created. A UTC timestamp with microseconds."},"updated_at":{"type":"string","format":"date-time","description":"When it last changed. Use it with `updated_since`. A UTC timestamp with microseconds."}},"example":{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","external_id":"deal-5531","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"qualified","priority":"medium","deal_type":"new_business","expected_close_on":"2026-12-15","one_time_cents":450000,"monthly_cents":15000,"created_at":"2026-10-12T14:10:00.000000Z","updated_at":"2026-10-20T15:41:02.118204Z"}},"Person":{"type":"object","required":["id","name","role"],"properties":{"id":{"type":"string","format":"uuid","description":"The person id. Use it as `assignee_id` and `user_id`."},"name":{"type":"string"},"first_name":{"type":["string","null"],"description":"Their first name, or null when the name has not been split."},"last_name":{"type":["string","null"],"description":"Their last name, or null when the name has not been split."},"role":{"type":"string","description":"Their role in the workspace."}},"additionalProperties":false,"example":{"id":"e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a81","name":"Priya Raman","first_name":"Priya","last_name":"Raman","role":"member"}},"Me":{"type":"object","required":["key","person","org","can_write","modules","limits"],"properties":{"key":{"type":"object","required":["id","name","prefix","kind","scopes","expires_at","rate_class"],"properties":{"id":{"type":"string","format":"uuid","description":"The key's id."},"name":{"type":"string"},"prefix":{"type":"string","description":"The eight characters after `mos_`, shown in your key list so you can tell keys apart."},"kind":{"type":"string","enum":["person","service"],"description":"`person` acts as the person who made it; `service` acts as its own non-human person."},"scopes":{"type":"array","items":{"type":"string","enum":["work:read","work:write","crm:read","crm:write"]}},"expires_at":{"type":"string","format":"date-time","description":"When the key stops working. A UTC timestamp with microseconds."},"rate_class":{"type":"string","enum":["basic","standard","scale"]}}},"person":{"type":"object","required":["user_id","role","name","is_service"],"properties":{"user_id":{"type":"string","format":"uuid","description":"Who the key acts as."},"role":{"type":"string"},"name":{"type":"string"},"is_service":{"type":"boolean"}}},"org":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string"}}},"can_write":{"type":"boolean","description":"True only if a write would be accepted right now."},"modules":{"type":"object","required":["work","people","api"],"properties":{"work":{"type":"boolean"},"people":{"type":"boolean"},"api":{"type":"boolean","description":"The API access add-on, needed for writes."}}},"limits":{"type":"object","required":["read_per_minute","write_per_minute","write_per_day"],"properties":{"read_per_minute":{"type":"integer"},"write_per_minute":{"type":"integer"},"write_per_day":{"type":"integer"}}}},"example":{"key":{"id":"c9d0e1f2-a3b4-4c5d-9e6f-7a8b9c0d1ec5","name":"Reporting script","prefix":"k3x9q2ab","kind":"service","scopes":["work:read","work:write"],"expires_at":"2027-01-18T00:00:00.000000Z","rate_class":"basic"},"person":{"user_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","role":"member","name":"API: Reporting script","is_service":true},"org":{"slug":"acme"},"can_write":true,"modules":{"work":true,"people":true,"api":true},"limits":{"read_per_minute":60,"write_per_minute":20,"write_per_day":300}}},"WriteItem":{"type":"object","required":["id"],"description":"The record as it now stands, with its `id` and its in-app `path`.","properties":{"id":{"type":"string","format":"uuid","description":"The record id."},"path":{"type":"string","description":"Where the record lives in the app."}},"additionalProperties":true,"example":{"id":"3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10","title":"Send the signed contract","path":"/work/tasks/3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}},"UpsertResult":{"type":"object","required":["id","match","external_id"],"additionalProperties":true,"description":"The company or contact as it now stands, with two added fields: `match` says what happened and `external_id` is your id for it (null when it has none).","properties":{"id":{"type":"string","format":"uuid","description":"The record id."},"match":{"type":"string","enum":["created","updated","unchanged"],"description":"`created` for a new record, `updated` when a matched record changed, `unchanged` when nothing needed to change or `on_match` was `skip`."},"external_id":{"type":["string","null"],"maxLength":128,"description":"Your id for this record."}},"example":{"id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","name":"Northwind Dental","external_id":"crm-1042","match":"created"}},"DealUpsertBody":{"type":"object","required":["external_id"],"additionalProperties":false,"description":"`name` and `stage` are used only when the deal is created; for a deal that exists they are ignored. `company_id` and `company_external_id` cannot both be sent. `one_time_cents` and `monthly_cents` need a key that acts as an owner, admin or finance person (403 `money_not_allowed` otherwise). `null` is not accepted for any field.","properties":{"external_id":{"type":"string","minLength":1,"maxLength":128,"description":"Your own id for this deal, 1 to 128 characters with no control characters. Required: it is the only way a deal is matched."},"name":{"type":"string","minLength":1,"maxLength":120,"description":"The deal name. Used when the deal is created; ignored for an existing deal."},"company_id":{"type":"string","format":"uuid","description":"A company id."},"company_external_id":{"type":"string","minLength":1,"maxLength":128,"description":"The `external_id` you gave the company. Another workspace's id never matches."},"deal_type":{"type":"string","enum":["new_business","existing_business"]},"stage":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$","description":"A stage key from GET /crm/stages. Used when the deal is created; ignored for an existing deal (use the stage call)."},"one_time_cents":{"type":"integer","minimum":0,"maximum":1000000000000,"description":"A one-time amount in whole cents. Needs a key that acts as an owner, admin or finance person (403 `money_not_allowed` otherwise)."},"monthly_cents":{"type":"integer","minimum":0,"maximum":1000000000000,"description":"A monthly amount in whole cents. Needs a key that acts as an owner, admin or finance person (403 `money_not_allowed` otherwise)."},"expected_close_on":{"type":"string","format":"date"},"description":{"type":"string","maxLength":500,"description":"Plain text. New lines are allowed."},"on_match":{"type":"string","enum":["update","fill_blanks","skip"],"description":"What to do when a record matches: `update` (default) overwrites the fields you send, `fill_blanks` fills only empty fields, `skip` changes nothing."}}},"DealStageBody":{"type":"object","required":["stage"],"additionalProperties":false,"description":"Send exactly one of `deal_id` and `external_id`.","oneOf":[{"required":["deal_id"]},{"required":["external_id"]}],"properties":{"deal_id":{"type":"string","format":"uuid","description":"The deal id."},"external_id":{"type":"string","minLength":1,"maxLength":128,"description":"The `external_id` you gave the deal."},"stage":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$","description":"The stage key to move to, from GET /crm/stages."},"reason":{"type":"string","maxLength":500,"description":"Why. Required when moving to a lost stage."}}},"DealUpsertResult":{"type":"object","required":["id","match","external_id"],"additionalProperties":true,"description":"The deal as it now stands, with `match` and your `external_id`. `one_time_cents` and `monthly_cents` appear only when the key acts as an owner, admin or finance person; for anyone else they are left out.","properties":{"id":{"type":"string","format":"uuid","description":"The deal id."},"name":{"type":"string"},"company_id":{"type":["string","null"],"format":"uuid","description":"The company."},"stage":{"type":"string"},"priority":{"type":"string"},"owner_id":{"type":["string","null"],"format":"uuid","description":"The deal owner."},"sales_agent_id":{"type":["string","null"],"format":"uuid","description":"The sales agent."},"expected_close_on":{"type":["string","null"],"format":"date"},"path":{"type":"string","description":"Where the deal lives in the app."},"one_time_cents":{"type":"integer","description":"Only when the key acts as an owner, admin or finance person."},"monthly_cents":{"type":"integer","description":"Only when the key acts as an owner, admin or finance person."},"match":{"type":"string","enum":["created","updated","unchanged"]},"external_id":{"type":["string","null"],"maxLength":128,"description":"Your id for this deal."}},"example":{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"qualified","priority":"medium","owner_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","sales_agent_id":null,"expected_close_on":"2026-12-15","path":"/crm/deals/3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","one_time_cents":450000,"monthly_cents":15000,"match":"created","external_id":"deal-5531"}},"DealStageResult":{"type":"object","required":["id","stage","external_id"],"additionalProperties":true,"description":"The deal after the move. Amounts are left out unless the key acts as an owner, admin or finance person. `external_id` is your id for the deal, null when it has none.","properties":{"id":{"type":"string","format":"uuid","description":"The deal id."},"name":{"type":"string"},"company_id":{"type":["string","null"],"format":"uuid","description":"The company."},"stage":{"type":"string"},"path":{"type":"string"},"external_id":{"type":["string","null"],"maxLength":128}},"example":{"id":"3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","name":"Northwind Dental: new website","company_id":"1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a41","stage":"proposal","priority":"medium","owner_id":"d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f70","sales_agent_id":null,"expected_close_on":"2026-12-15","path":"/crm/deals/3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c63","external_id":"deal-5531"}},"Notice":{"type":"object","required":["code","message"],"additionalProperties":false,"description":"Present once, on the write that takes the key's daily write count to 80 or 100 percent of its cap. Absent otherwise.","properties":{"code":{"type":"string","enum":["write_limit_80","write_limit_100"]},"message":{"type":"string"}},"example":{"code":"write_limit_80","message":"This key has used 80 percent of its daily write limit."}},"Error":{"type":"object","required":["error"],"additionalProperties":false,"example":{"error":{"code":"not_found","message":"That item was not found, or this key cannot see it.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}},"properties":{"error":{"type":"object","required":["code","message","request_id"],"additionalProperties":false,"properties":{"code":{"type":"string","enum":["bad_request","idempotency_key_required","unsupported_version","invalid_key","forbidden","module_off","two_factor_required","origin_not_allowed","money_not_allowed","not_found","method_not_allowed","workspace_read_only","ambiguous_match","payload_too_large","unsupported_media_type","idempotency_conflict","rate_limited","internal","unavailable"],"description":"A stable machine code. Branch on this, not on the message."},"message":{"type":"string","description":"A plain sentence for a person. It never repeats what you sent."},"request_id":{"type":"string","description":"Quote this when you ask for help. On writes it is your Idempotency-Key (a UUID lowercased, or a short key turned into a UUID); on reads a fresh uuid. Also in the X-Request-Id header."},"fields":{"type":"array","maxItems":20,"description":"On a 400 about the input: which inputs were wrong and why. Never the text you sent.","items":{"type":"object","required":["field","problem"],"additionalProperties":false,"properties":{"field":{"type":["string","null"]},"problem":{"type":"string","enum":["required","invalid","unknown_field"]}}}}}}}},"CompanyUpsertBody":{"type":"object","required":["name"],"additionalProperties":false,"properties":{"external_id":{"type":"string","minLength":1,"maxLength":128,"description":"Your own id for this record, 1 to 128 characters with no control characters. Send the same one again to update the same record."},"name":{"type":"string","minLength":1,"maxLength":120,"description":"The company name. Used to match when there is no `external_id` match."},"website":{"type":"string","maxLength":300},"address":{"type":"string","maxLength":500},"business_type":{"type":"string","maxLength":120},"importance":{"type":"integer","minimum":1,"maximum":5},"description":{"type":"string","maxLength":2000,"description":"Plain text. New lines are allowed."},"crm_status":{"type":"string","enum":["prospect","active","not_active","blacklisted"]},"contact_email":{"type":"string","maxLength":300,"description":"A general email address for the company."},"on_match":{"type":"string","enum":["update","fill_blanks","skip"],"description":"What to do when a record matches: `update` (default) overwrites the fields you send, `fill_blanks` fills only empty fields, `skip` changes nothing."}}},"ContactUpsertBody":{"type":"object","additionalProperties":false,"description":"Send an `external_id` or an `email`, or both. `company_id` and `company_external_id` cannot both be sent.","anyOf":[{"required":["external_id"]},{"required":["email"]}],"properties":{"external_id":{"type":"string","minLength":1,"maxLength":128,"description":"Your own id for this record, 1 to 128 characters with no control characters. Send the same one again to update the same record."},"first_name":{"type":"string","maxLength":300},"last_name":{"type":"string","maxLength":300},"email":{"type":"string","maxLength":300,"description":"Used to match when there is no `external_id` match."},"phone":{"type":"string","maxLength":60},"title":{"type":"string","maxLength":120},"company_id":{"type":"string","format":"uuid","description":"A company id."},"company_external_id":{"type":"string","minLength":1,"maxLength":128,"description":"The `external_id` you gave the company. Another workspace's id never matches."},"is_primary":{"type":"boolean","description":"Make this the company's main contact."},"role":{"type":"string","enum":["decision_maker","employee"]},"status":{"type":"string","enum":["active","not_active","on_hold","pitch_list","blacklisted"]},"lead_source":{"type":"string","enum":["direct","email","google_ads","maven_edu_website","store","website","website_funnel_page","phone_call","referral","social_media","upwork","word_of_mouth","meta_ads","other","google"]},"marketing_campaign":{"type":"string","maxLength":120},"notes":{"type":"string","maxLength":4000,"description":"Plain text. New lines are allowed."},"on_match":{"type":"string","enum":["update","fill_blanks","skip"],"description":"What to do when a record matches: `update` (default) overwrites the fields you send, `fill_blanks` fills only empty fields, `skip` changes nothing."}}},"CreateTaskBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200,"description":"The task title."},"description":{"type":"string","maxLength":4000},"project_id":{"type":"string","format":"uuid","description":"A project id from GET /projects."},"phase_id":{"type":"string","format":"uuid","description":"A phase id of that project."},"priority":{"type":"string","enum":["low","medium","high","urgent"],"description":"Default medium."},"due_on":{"type":"string","format":"date","description":"The due date as YYYY-MM-DD."},"assignee_ids":{"type":"array","maxItems":50,"items":{"type":"string","format":"uuid","description":"A person id from GET /people."},"description":"Workspace members to assign, by person id."},"client_id":{"type":"string","format":"uuid","description":"A client id."},"team_id":{"type":"string","format":"uuid","description":"A team id."},"estimate_minutes":{"type":"integer","minimum":1,"maximum":6000},"visibility":{"type":"string","enum":["public","private"],"description":"Default public. A private task is seen only by its creator and assignees (and owners and admins)."}},"required":["title"],"additionalProperties":false},"UpdateTaskBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":["string","null"],"maxLength":4000},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"due_on":{"type":["string","null"],"format":"date","description":"YYYY-MM-DD, or null to clear."},"estimate_minutes":{"type":["integer","null"],"minimum":1,"maximum":6000}},"required":[],"additionalProperties":false,"minProperties":1},"SetTaskStatusBody":{"type":"object","properties":{"status":{"type":"string","enum":["open","in_progress","done","cancelled"]}},"required":["status"],"additionalProperties":false},"AssignTaskBody":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid","description":"A person id from GET /people."}},"required":["user_id"],"additionalProperties":false},"AddTaskCommentBody":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000,"description":"The comment text."}},"required":["body"],"additionalProperties":false},"CreateProjectBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"client_id":{"type":"string","format":"uuid","description":"A client id."},"start_date":{"type":"string","format":"date","description":"The start date as YYYY-MM-DD."},"end_date":{"type":"string","format":"date","description":"The end date, not before the start date as YYYY-MM-DD."},"status":{"type":"string","enum":["planning","active","on_hold","complete"]}},"required":["name"],"additionalProperties":false},"UpdateProjectBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"client_id":{"type":["string","null"],"format":"uuid","description":"A client id."},"start_date":{"type":["string","null"],"format":"date","description":"YYYY-MM-DD, or null to clear."},"end_date":{"type":["string","null"],"format":"date","description":"YYYY-MM-DD, or null to clear."},"status":{"type":"string","enum":["planning","active","on_hold","complete"]}},"required":[],"additionalProperties":false,"minProperties":1},"AddProjectNoteBody":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000,"description":"The note text."},"task_id":{"type":"string","format":"uuid","description":"A task of this project."},"phase_id":{"type":"string","format":"uuid","description":"A phase id of that project."},"pinned":{"type":"boolean","description":"Pin the note to the top (default false)."}},"required":["body"],"additionalProperties":false}},"parameters":{"Org":{"name":"org","in":"path","required":true,"description":"Your workspace's short name, the part of the app address after the first slash. A key only works in its own workspace.","schema":{"type":"string"},"example":"acme"},"TaskId":{"name":"id","in":"path","required":true,"description":"The task id.","schema":{"type":"string","format":"uuid"}},"ProjectId":{"name":"id","in":"path","required":true,"description":"The project id.","schema":{"type":"string","format":"uuid"}},"CompanyId":{"name":"id","in":"path","required":true,"description":"The company id.","schema":{"type":"string","format":"uuid"}},"ContactId":{"name":"id","in":"path","required":true,"description":"The contact id.","schema":{"type":"string","format":"uuid"}},"DealId":{"name":"id","in":"path","required":true,"description":"The deal id.","schema":{"type":"string","format":"uuid"}},"CompanyIdFilter":{"name":"company_id","in":"query","required":false,"description":"Only records of this company.","schema":{"type":"string","format":"uuid"}},"DealStageFilter":{"name":"stage","in":"query","required":false,"description":"Only deals in this stage, a stage key from GET /crm/stages.","schema":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$"}},"Limit":{"name":"limit","in":"query","required":false,"description":"How many items to return, 1 to 100. Default 50.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},"After":{"name":"after","in":"query","required":false,"description":"The `next_cursor` of the previous page. Opaque; do not build or change it.","schema":{"type":"string","example":"v1.2026-10-20T14:03:11.482913Z.3f1c0c9e-5a3b-4a4e-9a52-1b7f3c0d2a10"}},"StatusTask":{"name":"status","in":"query","required":false,"description":"Only tasks with this status.","schema":{"type":"string","enum":["open","in_progress","done","cancelled"]}},"StatusProject":{"name":"status","in":"query","required":false,"description":"Only projects with this status.","schema":{"type":"string","enum":["planning","active","on_hold","complete"]}},"ProjectIdFilter":{"name":"project_id","in":"query","required":false,"description":"Only tasks in this project.","schema":{"type":"string","format":"uuid"}},"AssigneeId":{"name":"assignee_id","in":"query","required":false,"description":"Only tasks assigned to this person.","schema":{"type":"string","format":"uuid"}},"ClientId":{"name":"client_id","in":"query","required":false,"description":"Only projects for this client.","schema":{"type":"string","format":"uuid"}},"UpdatedSince":{"name":"updated_since","in":"query","required":false,"description":"Only records changed at or after this moment. An ISO date or timestamp.","schema":{"type":"string","format":"date-time"}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{8,64}$"},"description":"A fresh key you make up for each change: a UUID, or 8 to 64 letters, digits, underscores or hyphens. Required on every POST and PATCH. Sending the same call again with the same key within 24 hours makes the change once and returns the first answer with `replayed: true`. The same key with a different call or body answers 422."},"Version":{"name":"MavenOS-Version","in":"header","required":false,"schema":{"type":"string","enum":["2026-10-21"]},"description":"Optional. The only accepted value is 2026-10-21."}},"headers":{"RateLimit-Limit":{"description":"Calls allowed in the current window for this kind of call (read or write).","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Calls left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets. For the daily write cap the window is the UTC calendar day: seconds until 00:00 UTC.","schema":{"type":"integer"}},"X-Request-Id":{"description":"Quote this when you ask for help. On writes it is your Idempotency-Key, lowercased.","schema":{"type":"string"}},"Idempotent-Replayed":{"description":"`true` when this answer is the first answer replayed for a repeated Idempotency-Key. Nothing was written again.","schema":{"type":"string","enum":["true"]}},"Location":{"description":"Where the new task or project can be read.","schema":{"type":"string"}},"Allow":{"description":"On a 405: the methods that work on this path.","schema":{"type":"string"}},"Retry-After":{"description":"On a 429: seconds to wait before trying again. After the daily write cap it is the seconds left until 00:00 UTC.","schema":{"type":"integer","minimum":0}}},"responses":{"BadRequest":{"description":"The request is malformed or breaks a limit. `fields` says which input and why.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"bad_request":{"summary":"bad_request","value":{"error":{"code":"bad_request","message":"The request was not valid. Check the fields and try again.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30","fields":[{"field":"title","problem":"required"}]}}},"idempotency_key_required":{"summary":"idempotency_key_required","value":{"error":{"code":"idempotency_key_required","message":"Send an Idempotency-Key header on every POST and PATCH: a UUID, or 8 to 64 letters, digits, underscores or hyphens.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}},"unsupported_version":{"summary":"unsupported_version","value":{"error":{"code":"unsupported_version","message":"That MavenOS-Version is not supported. Use 2026-10-21 or leave the header out.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"InvalidKey":{"description":"The key was not accepted. The answer is identical for every cause (including a wrong workspace name), so it never reveals why.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"WWW-Authenticate":{"description":"Always `Bearer realm=\"mavenos-api\"`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_key":{"summary":"invalid_key","value":{"error":{"code":"invalid_key","message":"That key is not valid. It may have been revoked or expired, or it belongs to another workspace.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"Forbidden":{"description":"The key may not do this, or the request came from a web page.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"forbidden","value":{"error":{"code":"forbidden","message":"This key is not allowed to do that.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}},"module_off":{"summary":"module_off","value":{"error":{"code":"module_off","message":"The part of MavenOS this needs is switched off for this workspace.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}},"two_factor_required":{"summary":"two_factor_required","value":{"error":{"code":"two_factor_required","message":"This workspace requires two-step sign-in, which API keys cannot provide.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}},"origin_not_allowed":{"summary":"origin_not_allowed","value":{"error":{"code":"origin_not_allowed","message":"Browser requests are not allowed. Call this API from a server.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}},"money_not_allowed":{"summary":"money_not_allowed","value":{"error":{"code":"money_not_allowed","message":"Setting deal amounts needs an owner, admin or finance role. Use a key that acts as one of them, or leave the amounts out.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"NotFound":{"description":"No such path or record, an id that is not a uuid, or a record the key's person may not read.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"error":{"code":"not_found","message":"That item was not found, or this key cannot see it.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"MethodNotAllowed":{"description":"That method is not offered on this path. Nothing can be deleted through the API.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Allow":{"$ref":"#/components/headers/Allow"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"method_not_allowed":{"summary":"method_not_allowed","value":{"error":{"code":"method_not_allowed","message":"That method is not allowed on this path.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"ReadOnly":{"description":"The workspace is read-only for this tool, or its trial has ended.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"workspace_read_only":{"summary":"workspace_read_only","value":{"error":{"code":"workspace_read_only","message":"This workspace is read-only right now, so nothing was saved.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"TooLarge":{"description":"The body is over 64 KB.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"payload_too_large","value":{"error":{"code":"payload_too_large","message":"The request body is too large.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"TooLargeCrm":{"description":"The body is over 32 KB.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"payload_too_large","value":{"error":{"code":"payload_too_large","message":"The request body is too large.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"UnsupportedMediaCrm":{"description":"The Content-Type is not exactly `application/json` (optionally followed by `; charset=utf-8`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unsupported_media_type":{"summary":"unsupported_media_type","value":{"error":{"code":"unsupported_media_type","message":"Send the body as application/json.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"Conflict":{"description":"The workspace is read-only for this tool, or the upsert matched more than one record and changed nothing.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"workspace_read_only":{"summary":"workspace_read_only","value":{"error":{"code":"workspace_read_only","message":"This workspace is read-only right now, so nothing was saved.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}},"ambiguous_match":{"summary":"ambiguous_match","value":{"error":{"code":"ambiguous_match","message":"More than one record matches. Nothing was changed. Send the external_id of the one you mean.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"UnsupportedMedia":{"description":"The body is not JSON.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unsupported_media_type":{"summary":"unsupported_media_type","value":{"error":{"code":"unsupported_media_type","message":"Send the body as application/json.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"IdempotencyConflict":{"description":"That Idempotency-Key was already used for a different call or body.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"idempotency_conflict":{"summary":"idempotency_conflict","value":{"error":{"code":"idempotency_conflict","message":"That Idempotency-Key was already used for a different request.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"RateLimited":{"description":"The key reached a rate cap. Wait the number of seconds in Retry-After.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"error":{"code":"rate_limited","message":"Too many requests for this key. Wait and try again.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"Internal":{"description":"Something went wrong on our side. Nothing was changed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"internal","value":{"error":{"code":"internal","message":"Something went wrong on our side and nothing was saved.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}},"Unavailable":{"description":"Temporarily unavailable. Try again; a change may be retried with the same Idempotency-Key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unavailable":{"summary":"unavailable","value":{"error":{"code":"unavailable","message":"Temporarily unavailable. Try again; a change may be retried with the same Idempotency-Key.","request_id":"0d1e2f3a-4b5c-4d6e-8f7a-8b9c0d1e2f30"}}}}}}}}}}