{"openapi":"3.1.0","info":{"title":"Zoho Projects/Sprints Gateway","version":"1.0.0","description":"Consumer-agnostic API for Zoho Projects and optional Zoho Sprints. Callers present a per-user gateway API key (from /wizard) or the operator GATEWAY_API_KEY. Reads go to Zoho immediately. Writes are a two-step queue: agents propose; a human approves. This service uses its own Zoho OAuth client, separate from any other Zoho integrations."},"servers":[{"url":"https://zoho-gateway.runit-solutions.com","description":"RunIT k3s (zoho-gateway.runit-solutions.com)"},{"url":"http://0.0.0.0:43147","description":"Local"}],"security":[{"gatewayApiKey":[]}],"tags":[{"name":"meta"},{"name":"projects"},{"name":"tasks"},{"name":"issues"},{"name":"search"},{"name":"sprints"},{"name":"writes"}],"paths":{"/health":{"get":{"tags":["meta"],"security":[],"summary":"Liveness","operationId":"health","responses":{"200":{"description":"OK"}}}},"/openapi.json":{"get":{"tags":["meta"],"security":[],"summary":"This OpenAPI document","operationId":"openapi","responses":{"200":{"description":"OpenAPI 3.1 JSON"}}}},"/meta":{"get":{"tags":["meta"],"summary":"Module map and write-gate status","operationId":"meta","responses":{"200":{"description":"Catalog"}}}},"/usage":{"get":{"tags":["meta"],"summary":"Zoho call count for the current UTC day","operationId":"usage","responses":{"200":{"description":"Usage"}}}},"/portals":{"get":{"tags":["projects"],"summary":"List portals","operationId":"listPortals","responses":{"200":{"description":"Portals"}}}},"/projects":{"get":{"tags":["projects"],"summary":"List projects (or search with q)","operationId":"listProjects","parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer"}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"q","in":"query","description":"If set, uses Zoho Search API (module=projects)","schema":{"type":"string"}}],"responses":{"200":{"description":"Projects"}}}},"/projects/{projectId}":{"get":{"tags":["projects"],"summary":"Get project","operationId":"getProject","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project"}}}},"/projects/{projectId}/tasks":{"get":{"tags":["tasks"],"summary":"List tasks (or search with q)","operationId":"listTasks","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer"}},{"name":"q","in":"query","schema":{"type":"string"}},{"name":"sort_by","in":"query","schema":{"type":"string"}},{"name":"filter","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Tasks"}}}},"/projects/{projectId}/tasks/{taskId}":{"get":{"tags":["tasks"],"summary":"Get task","operationId":"getTask","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"taskId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Task"}}}},"/projects/{projectId}/issues":{"get":{"tags":["issues"],"summary":"List issues (or search with q)","operationId":"listIssues","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer"}},{"name":"q","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Issues"}}}},"/projects/{projectId}/issues/{issueId}":{"get":{"tags":["issues"],"summary":"Get issue","operationId":"getIssue","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"issueId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Issue"}}}},"/search":{"get":{"tags":["search"],"summary":"Portal or project search","operationId":"search","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}},{"name":"module","in":"query","schema":{"type":"string"}},{"name":"project_id","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Search hits"}}}},"/projects/{projectId}/sprints":{"get":{"tags":["sprints"],"summary":"List sprints (Zoho Sprints product; needs ZOHO_SPRINTS_TEAM_ID)","operationId":"listSprints","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer"}},{"name":"type","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Sprints"}}}},"/projects/{projectId}/sprints/project":{"get":{"tags":["sprints"],"summary":"Zoho Sprints project details (kanbanBoardId)","operationId":"getSprintsProject","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sprints project"}}}},"/projects/{projectId}/sprints/{sprintId}/items":{"get":{"tags":["sprints"],"summary":"Sprint board items","operationId":"listSprintItems","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"sprintId","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Items"}}}},"/writes":{"get":{"tags":["writes"],"summary":"List this API key's write proposals. Write routes are on (ZOHO_GATEWAY_WRITES=1). POST/PATCH only *propose* a pending mutation. Zoho is called only after a human approves in /wizard or POST /writes/{id}/approve with confirm=true.","operationId":"listWrites","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["pending","approved","rejected","failed"]}}],"responses":{"200":{"description":"Write queue"},"403":{"description":"Writes disabled"}}}},"/writes/{id}":{"get":{"tags":["writes"],"summary":"Get one write proposal","operationId":"getWrite","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Write proposal"},"404":{"description":"Not found for this API key"}}}},"/writes/approve-all":{"post":{"tags":["writes"],"summary":"Human on-command: approve pending writes serially (delay between Zoho calls). Requires confirm=true. Not for agents.","operationId":"batchApproveWrites","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["confirm"],"properties":{"confirm":{"type":"boolean"},"ids":{"type":"array","items":{"type":"string"},"description":"Optional subset. Default: all pending for this key."}}}}}},"responses":{"200":{"description":"Per-item summary (continues after failures)"},"400":{"description":"confirm=true missing"}}}},"/writes/reject-all":{"post":{"tags":["writes"],"summary":"Human on-command: reject pending writes. Requires confirm=true. Not for agents.","operationId":"batchRejectWrites","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["confirm"],"properties":{"confirm":{"type":"boolean"},"ids":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Per-item summary"},"400":{"description":"confirm=true missing"}}}},"/writes/{id}/approve":{"post":{"tags":["writes"],"summary":"Human on-command: send a pending write to Zoho. Requires confirm=true. Not for agents.","operationId":"approveWrite","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be true. Human on-command only; agents must not set this."}}}}}},"responses":{"200":{"description":"Approved and sent to Zoho"},"400":{"description":"confirm=true missing"},"409":{"description":"Not pending"}}}},"/writes/{id}/reject":{"post":{"tags":["writes"],"summary":"Human on-command: reject a pending write. Requires confirm=true. Not for agents.","operationId":"rejectWrite","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be true. Human on-command only; agents must not set this."}}}}}},"responses":{"200":{"description":"Rejected"},"400":{"description":"confirm=true missing"}}}},"/writes/projects/{projectId}/tasks":{"post":{"tags":["writes"],"summary":"Propose creating a task (does not call Zoho). Write routes are on (ZOHO_GATEWAY_WRITES=1). POST/PATCH only *propose* a pending mutation. Zoho is called only after a human approves in /wizard or POST /writes/{id}/approve with confirm=true.","operationId":"createTask","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dry_run":{"type":"boolean","description":"If true, preview only — nothing is stored or sent to Zoho."},"name":{"type":"string"},"description":{"type":"string"},"status":{"type":"object"}}}}}},"responses":{"200":{"description":"Dry-run preview"},"201":{"description":"Pending write stored"},"403":{"description":"Writes disabled"}}}},"/writes/projects/{projectId}/tasks/{taskId}":{"patch":{"tags":["writes"],"summary":"Propose updating a task (does not call Zoho). Write routes are on (ZOHO_GATEWAY_WRITES=1). POST/PATCH only *propose* a pending mutation. Zoho is called only after a human approves in /wizard or POST /writes/{id}/approve with confirm=true.","operationId":"updateTask","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}},{"name":"taskId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dry_run":{"type":"boolean"},"name":{"type":"string"},"status":{"type":"object"}}}}}},"responses":{"200":{"description":"Pending write stored or dry-run"},"403":{"description":"Writes disabled"}}}}},"components":{"securitySchemes":{"gatewayApiKey":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"Per-user key from /wizard, or the operator GATEWAY_API_KEY. Same header shape either way."}}}}