{"openapi":"3.1.0","info":{"title":"TPP Public REST API — The Power Plugin","summary":"Machine-readable REST surface for The Power Plugin (TPP).","description":"Bearer-authenticated REST API for The Power Plugin (TPP). Tokens look like `tpp_<hex>` and are scoped to a billing company. User-bound tokens (`acting_user_id`) also unlock the hosted MCP server at `/api/mcp` and task comments.\n\nHuman docs: https://docs.thepowerplugin.com/flow\nOpenAPI: https://www.thepowerplugin.com/openapi.json\nMCP card: https://www.thepowerplugin.com/.well-known/mcp.json\nDevelopers: https://www.thepowerplugin.com/developers","version":"1.0.0","contact":{"name":"The Power Plugin API","url":"https://www.thepowerplugin.com/developers","email":"sales@thepowerplugin.com"}},"servers":[{"url":"https://www.thepowerplugin.com","description":"Production"}],"tags":[{"name":"Clients","description":"Tenant-scoped client companies."},{"name":"Projects","description":"Projects belonging to a client."},{"name":"Tasks","description":"Work items. A task links to at most one of project, client or provider."},{"name":"Comments","description":"Task comments. Requires a user-bound token."},{"name":"Invoices","description":"tpp-ops external-order invoices."},{"name":"Purchases","description":"tpp-ops supplier purchases (payables) without a sales invoice."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"tpp_<hex>","description":"Long-lived API token. Send `Authorization: Bearer tpp_<48 hex chars>`. Tokens are hashed at rest (SHA-256). Company-scoped tokens authorize `/api/v1/*` by `permissions[]`. User-bound tokens (`acting_user_id`) additionally authorize MCP tools and comments, and inherit that user’s RBAC."}},"schemas":{"ErrorEnvelope":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}},"Client":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"legal_name":{"type":"string","nullable":true},"billing_email":{"type":"string","nullable":true},"country":{"type":"string","nullable":true,"maxLength":2},"notes":{"type":"string","nullable":true},"slug":{"type":"string"},"lifecycle_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"Project":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"scope":{"type":"string","nullable":true},"status":{"type":"string","enum":["active","paused","completed","cancelled"]},"billing_type":{"type":"string","enum":["subscription","fixed","free"]}}},"Task":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string","enum":["backlog","todo","in_progress","blocked","in_review","done","disputed","cancelled"]},"project_id":{"type":"string","format":"uuid","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"provider_id":{"type":"string","format":"uuid","nullable":true},"assigned_worker_id":{"type":"string","format":"uuid","nullable":true},"billing_mode":{"type":"string","enum":["fixed","included"]},"client_price":{"type":"number"},"worker_price":{"type":"number"}}},"Comment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"body":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"Invoice":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_order_id":{"type":"string"},"public_id":{"type":"integer","nullable":true},"client_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft","pending_payment","collected","paid_to_worker","cancelled"]},"amount_total":{"type":"number"},"tax_amount":{"type":"number"}}},"Purchase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_purchase_id":{"type":"string"},"status":{"type":"string"},"supplier_name":{"type":"string","nullable":true}}}}},"security":[{"bearerAuth":[]}],"paths":{"/api/v1/clients":{"get":{"operationId":"listClients","tags":["Clients"],"summary":"List clients","description":"Paginated list of clients in the token’s billing company. Optional `search` filters by name.","parameters":[{"name":"page","in":"query","description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","description":"Page size (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"search","in":"query","description":"Case-insensitive name/title filter.","schema":{"type":"string"}}],"responses":{"200":{"description":"Client page.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"legal_name":{"type":"string","nullable":true},"billing_email":{"type":"string","nullable":true},"country":{"type":"string","nullable":true,"maxLength":2},"notes":{"type":"string","nullable":true},"slug":{"type":"string"},"lifecycle_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"post":{"operationId":"createClient","tags":["Clients"],"summary":"Create a client","description":"Creates a client in this billing company. Names are unique per company.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"legal_name":{"type":"string","maxLength":255},"billing_email":{"type":"string","format":"email"},"country":{"type":"string","minLength":2,"maxLength":2},"notes":{"type":"string"}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"legal_name":{"type":"string","nullable":true},"billing_email":{"type":"string","nullable":true},"country":{"type":"string","nullable":true,"maxLength":2},"notes":{"type":"string","nullable":true},"slug":{"type":"string"},"lifecycle_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/clients/{id}":{"get":{"operationId":"getClient","tags":["Clients"],"summary":"Get a client","description":"Fetch one client by UUID. 404 if it is not in this token’s company.","parameters":[{"name":"id","in":"path","required":true,"description":"Client UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Client.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"legal_name":{"type":"string","nullable":true},"billing_email":{"type":"string","nullable":true},"country":{"type":"string","nullable":true,"maxLength":2},"notes":{"type":"string","nullable":true},"slug":{"type":"string"},"lifecycle_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"put":{"operationId":"updateClient","tags":["Clients"],"summary":"Update a client","description":"Partial update of name, legal_name, billing_email, country or notes.","parameters":[{"name":"id","in":"path","required":true,"description":"Client UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"legal_name":{"type":"string","nullable":true},"billing_email":{"type":"string","nullable":true},"country":{"type":"string","nullable":true,"maxLength":2},"notes":{"type":"string","nullable":true},"slug":{"type":"string"},"lifecycle_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"delete":{"operationId":"deleteClient","tags":["Clients"],"summary":"Delete a client","description":"Deletes the client if it belongs to this token’s company.","parameters":[{"name":"id","in":"path","required":true,"description":"Client UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object"},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/projects":{"get":{"operationId":"listProjects","tags":["Projects"],"summary":"List projects","description":"Paginated projects. User-bound tokens honour RBAC; company tokens list the whole tenant. Filter with `client_id`, `status`, `search`.","parameters":[{"name":"page","in":"query","description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","description":"Page size (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"search","in":"query","description":"Case-insensitive name/title filter.","schema":{"type":"string"}},{"name":"client_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filter by client."},{"name":"status","in":"query","schema":{"type":"string"},"description":"Filter by project status."}],"responses":{"200":{"description":"Project page.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"scope":{"type":"string","nullable":true},"status":{"type":"string","enum":["active","paused","completed","cancelled"]},"billing_type":{"type":"string","enum":["subscription","fixed","free"]}}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"post":{"operationId":"createProject","tags":["Projects"],"summary":"Create a project","description":"Creates a project under a client that belongs to this token’s company.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_id","title"],"properties":{"client_id":{"type":"string","format":"uuid"},"title":{"type":"string","minLength":1,"maxLength":255},"scope":{"type":"string"},"status":{"type":"string","enum":["active","paused","completed","cancelled"]},"billing_type":{"type":"string","enum":["subscription","fixed","free"]}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"scope":{"type":"string","nullable":true},"status":{"type":"string","enum":["active","paused","completed","cancelled"]},"billing_type":{"type":"string","enum":["subscription","fixed","free"]}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/projects/{id}":{"get":{"operationId":"getProject","tags":["Projects"],"summary":"Get a project","description":"Fetch one project by UUID if it belongs to this token’s company.","parameters":[{"name":"id","in":"path","required":true,"description":"Project UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Project.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"scope":{"type":"string","nullable":true},"status":{"type":"string","enum":["active","paused","completed","cancelled"]},"billing_type":{"type":"string","enum":["subscription","fixed","free"]}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"put":{"operationId":"updateProject","tags":["Projects"],"summary":"Update a project","description":"Partial update of title, scope, status or billing_type.","parameters":[{"name":"id","in":"path","required":true,"description":"Project UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"scope":{"type":"string","nullable":true},"status":{"type":"string","enum":["active","paused","completed","cancelled"]},"billing_type":{"type":"string","enum":["subscription","fixed","free"]}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"delete":{"operationId":"deleteProject","tags":["Projects"],"summary":"Delete a project","description":"Deletes the project if it belongs to this token’s company.","parameters":[{"name":"id","in":"path","required":true,"description":"Project UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object"},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/tasks":{"get":{"operationId":"listTasks","tags":["Tasks"],"summary":"List tasks","description":"Paginated tasks. User-bound tokens apply RBAC (`own` vs `all`). Filter with `project_id`, `client_id`, `status`, `search`.","parameters":[{"name":"page","in":"query","description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","description":"Page size (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"search","in":"query","description":"Case-insensitive name/title filter.","schema":{"type":"string"}},{"name":"project_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"client_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string","enum":["backlog","todo","in_progress","blocked","in_review","done","disputed","cancelled"]}}],"responses":{"200":{"description":"Task page.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string","enum":["backlog","todo","in_progress","blocked","in_review","done","disputed","cancelled"]},"project_id":{"type":"string","format":"uuid","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"provider_id":{"type":"string","format":"uuid","nullable":true},"assigned_worker_id":{"type":"string","format":"uuid","nullable":true},"billing_mode":{"type":"string","enum":["fixed","included"]},"client_price":{"type":"number"},"worker_price":{"type":"number"}}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"post":{"operationId":"createTask","tags":["Tasks"],"summary":"Create a task","description":"Creates a task. Link to at most one of `project_id`, `client_id` or `provider_id`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","minLength":1,"maxLength":500},"description_html":{"type":"string"},"status":{"type":"string","enum":["backlog","todo","in_progress","blocked","in_review","done","disputed","cancelled"]},"project_id":{"type":"string","format":"uuid","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"provider_id":{"type":"string","format":"uuid","nullable":true},"assigned_worker_id":{"type":"string","format":"uuid","nullable":true},"billing_mode":{"type":"string","enum":["fixed","included"]},"client_price":{"type":"number","minimum":0},"worker_price":{"type":"number","minimum":0}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string","enum":["backlog","todo","in_progress","blocked","in_review","done","disputed","cancelled"]},"project_id":{"type":"string","format":"uuid","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"provider_id":{"type":"string","format":"uuid","nullable":true},"assigned_worker_id":{"type":"string","format":"uuid","nullable":true},"billing_mode":{"type":"string","enum":["fixed","included"]},"client_price":{"type":"number"},"worker_price":{"type":"number"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/tasks/{id}":{"get":{"operationId":"getTask","tags":["Tasks"],"summary":"Get a task","description":"`id` is a UUID. (MCP `get_task` also accepts task_code, public_id or an admin URL.)","parameters":[{"name":"id","in":"path","required":true,"description":"Task UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Task.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string","enum":["backlog","todo","in_progress","blocked","in_review","done","disputed","cancelled"]},"project_id":{"type":"string","format":"uuid","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"provider_id":{"type":"string","format":"uuid","nullable":true},"assigned_worker_id":{"type":"string","format":"uuid","nullable":true},"billing_mode":{"type":"string","enum":["fixed","included"]},"client_price":{"type":"number"},"worker_price":{"type":"number"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"put":{"operationId":"updateTask","tags":["Tasks"],"summary":"Update a task","description":"Partial update of title, status, assignment, billing or relation fields.","parameters":[{"name":"id","in":"path","required":true,"description":"Task UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string","enum":["backlog","todo","in_progress","blocked","in_review","done","disputed","cancelled"]},"project_id":{"type":"string","format":"uuid","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"provider_id":{"type":"string","format":"uuid","nullable":true},"assigned_worker_id":{"type":"string","format":"uuid","nullable":true},"billing_mode":{"type":"string","enum":["fixed","included"]},"client_price":{"type":"number"},"worker_price":{"type":"number"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"delete":{"operationId":"deleteTask","tags":["Tasks"],"summary":"Delete a task","description":"Deletes the task if the token may access it.","parameters":[{"name":"id","in":"path","required":true,"description":"Task UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object"},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/tasks/{id}/comments":{"get":{"operationId":"listTaskComments","tags":["Comments"],"summary":"List comments on a task","description":"Requires a user-bound token (`acting_user_id`). Company-scoped integration tokens are rejected with 401.","parameters":[{"name":"id","in":"path","required":true,"description":"Task UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Comments.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"body":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}},"post":{"operationId":"addTaskComment","tags":["Comments"],"summary":"Add a comment","description":"Markdown body. Optional `mentioned_worker_ids`. Requires a user-bound token.","parameters":[{"name":"id","in":"path","required":true,"description":"Task UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body"],"properties":{"body":{"type":"string","minLength":1},"mentioned_worker_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"body":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/invoices":{"post":{"operationId":"createOrSyncInvoice","tags":["Invoices"],"summary":"Create or sync an invoice from an external order","description":"Idempotent on `external_order_id`. First call creates a draft/pending_payment invoice (201). Repeats while draft/pending_payment fully sync (200). Collected/paid/cancelled invoices are returned unchanged (200). `brand_id` must resolve to a client in this token’s billing company.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["external_order_id","brand_id","line_items"],"properties":{"external_order_id":{"type":"string","minLength":1,"maxLength":120},"brand_id":{"type":"string","minLength":1,"maxLength":120},"supplier_name":{"type":"string"},"supplier_currency":{"type":"string","minLength":3,"maxLength":3},"notes":{"type":"string"},"status":{"type":"string","enum":["draft","pending_payment"]},"discount_type":{"type":"string","enum":["none","fixed","percent"]},"discount_value":{"type":"number","minimum":0},"line_items":{"type":"array","minItems":1,"items":{"type":"object","required":["description","amount_cents"],"properties":{"description":{"type":"string"},"amount_cents":{"type":"integer","minimum":0},"discount_cents":{"type":"integer","minimum":0},"cost_cents":{"type":"integer","minimum":0},"cost_currency":{"type":"string","minLength":3,"maxLength":3}}}}}}}}},"responses":{"200":{"description":"Synced existing invoice.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_order_id":{"type":"string"},"public_id":{"type":"integer","nullable":true},"client_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft","pending_payment","collected","paid_to_worker","cancelled"]},"amount_total":{"type":"number"},"tax_amount":{"type":"number"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_order_id":{"type":"string"},"public_id":{"type":"integer","nullable":true},"client_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft","pending_payment","collected","paid_to_worker","cancelled"]},"amount_total":{"type":"number"},"tax_amount":{"type":"number"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/invoices/{external_order_id}":{"get":{"operationId":"getInvoiceByExternalOrderId","tags":["Invoices"],"summary":"Get an invoice by external order id","description":"Read the current state of an invoice created from a tpp-ops external order.","parameters":[{"name":"external_order_id","in":"path","required":true,"schema":{"type":"string"},"description":"tpp-ops order id used at creation."}],"responses":{"200":{"description":"Invoice.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_order_id":{"type":"string"},"public_id":{"type":"integer","nullable":true},"client_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft","pending_payment","collected","paid_to_worker","cancelled"]},"amount_total":{"type":"number"},"tax_amount":{"type":"number"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/invoices/{external_order_id}/cancel":{"post":{"operationId":"cancelInvoice","tags":["Invoices"],"summary":"Cancel an invoice","description":"Cancels the invoice for this external order. Optional `reason`.","parameters":[{"name":"external_order_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Cancelled.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_order_id":{"type":"string"},"public_id":{"type":"integer","nullable":true},"client_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft","pending_payment","collected","paid_to_worker","cancelled"]},"amount_total":{"type":"number"},"tax_amount":{"type":"number"}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/purchases":{"post":{"operationId":"createOrSyncPurchase","tags":["Purchases"],"summary":"Create or sync a supplier purchase","description":"Used by tpp-ops for prepaid/monthly orders that have no sales invoice. Idempotent on `external_purchase_id`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["external_purchase_id","brand_id"],"properties":{"external_purchase_id":{"type":"string","minLength":1,"maxLength":120},"brand_id":{"type":"string","minLength":1},"supplier_name":{"type":"string"},"notes":{"type":"string"}}}}}},"responses":{"200":{"description":"Synced.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_purchase_id":{"type":"string"},"status":{"type":"string"},"supplier_name":{"type":"string","nullable":true}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_purchase_id":{"type":"string"},"status":{"type":"string"},"supplier_name":{"type":"string","nullable":true}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/purchases/{external_purchase_id}":{"get":{"operationId":"getPurchaseByExternalId","tags":["Purchases"],"summary":"Get a purchase by external id","description":"Read a supplier purchase (payable) created from tpp-ops.","parameters":[{"name":"external_purchase_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Purchase.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_purchase_id":{"type":"string"},"status":{"type":"string"},"supplier_name":{"type":"string","nullable":true}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}},"/api/v1/purchases/{external_purchase_id}/cancel":{"post":{"operationId":"cancelPurchase","tags":["Purchases"],"summary":"Cancel a purchase","description":"Voids the payable (`status=void`).","parameters":[{"name":"external_purchase_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cancelled.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_purchase_id":{"type":"string"},"status":{"type":"string"},"supplier_name":{"type":"string","nullable":true}}},"error":{"nullable":true,"default":null},"pagination":{"type":"object","nullable":true,"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}}}}}}},"401":{"description":"Missing, invalid, or insufficient API token.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}},"404":{"description":"Resource not found in this token’s tenant.","content":{"application/json":{"schema":{"type":"object","required":["data","error","pagination"],"properties":{"data":{"nullable":true,"default":null},"error":{"type":"string"},"pagination":{"nullable":true,"default":null}}}}}}}}}}}