{"openapi":"3.0.3","info":{"title":"ProductOS API","version":"1.0.0","description":"Public REST API for ProductOS. Authenticate with `Authorization: Bearer <api key>` (create keys in Settings → API keys). Rate limits depend on your plan. Outbound webhooks are signed with HMAC-SHA256 in the `X-ProductOS-Signature` header (`t=<unix>,v1=<hex>` over `\"{t}.{body}\"`)."},"servers":[{"url":"/api/v1"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"API key from Settings → API keys"}}},"paths":{"/features":{"get":{"summary":"List features","security":[{"apiKey":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["IDEA","DISCOVERY","PLANNED","IN_PROGRESS","SHIPPED","CANCELLED"]}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","description":"Opaque cursor from a previous response's nextCursor","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as ?cursor= to fetch the next page; null when exhausted"}}}}}}}},"post":{"summary":"Create a feature","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"status":{"type":"string","enum":["IDEA","DISCOVERY","PLANNED","IN_PROGRESS","SHIPPED","CANCELLED"]},"reach":{"type":"integer"},"impact":{"type":"number"},"confidence":{"type":"integer"},"effort":{"type":"number"},"tags":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}}}}},"/features/{id}":{"get":{"summary":"Get a feature","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"404":{"description":"Not found"}}},"patch":{"summary":"Update a feature","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"404":{"description":"Not found"}}}},"/feedback":{"get":{"summary":"List feedback","security":[{"apiKey":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","description":"Opaque cursor from a previous response's nextCursor","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as ?cursor= to fetch the next page; null when exhausted"}}}}}}}},"post":{"summary":"Submit feedback","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"body":{"type":"string"},"customerName":{"type":"string"},"customerEmail":{"type":"string","format":"email"},"sentiment":{"type":"integer","minimum":-1,"maximum":1},"tags":{"type":"array","items":{"type":"string"}},"externalId":{"type":"string"},"externalUrl":{"type":"string"}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}}}}},"/tasks":{"get":{"summary":"List tasks","security":[{"apiKey":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["TODO","IN_PROGRESS","IN_REVIEW","DONE"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","description":"Opaque cursor from a previous response's nextCursor","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as ?cursor= to fetch the next page; null when exhausted"}}}}}}}},"post":{"summary":"Create a task","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"sprintId":{"type":"string"},"featureId":{"type":"string"},"estimate":{"type":"integer"},"status":{"type":"string","enum":["TODO","IN_PROGRESS","IN_REVIEW","DONE"]}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}}}}},"/boards":{"get":{"summary":"List boards","description":"Boards in the authenticated workspace, most recently updated first. Each row includes `_count.items`.","security":[{"apiKey":[]}],"parameters":[{"name":"search","in":"query","description":"Case-insensitive match on the board name","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","description":"Opaque cursor from a previous response's nextCursor","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as ?cursor= to fetch the next page; null when exhausted"}}}}}}}},"post":{"summary":"Create a board","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":120},"description":{"type":"string"},"template":{"type":"string","maxLength":60,"description":"Template key to stamp on the board, e.g. retro or story-map","example":"retro"}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"400":{"description":"Invalid request body"}}}},"/boards/{id}":{"get":{"summary":"Get a board with its items","description":"Returns the board plus every item ordered by `z` then creation time.","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"404":{"description":"Not found"}}},"patch":{"summary":"Update a board","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"description":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"400":{"description":"Invalid request body"},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a board","description":"Deletes the board and, by cascade, all of its items and votes.","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"404":{"description":"Not found"}}}},"/boards/{id}/items":{"get":{"summary":"List board items","description":"Items on a board, ordered back-to-front by `z`. Each row includes `_count.votes`.","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","description":"Opaque cursor from a previous response's nextCursor","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as ?cursor= to fetch the next page; null when exhausted"}}}}}},"404":{"description":"Not found"}}},"post":{"summary":"Add an item to a board","description":"`featureId` / `feedbackId` link the item to an existing record in the same workspace.","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["x","y"],"properties":{"type":{"type":"string","enum":["STICKY","SHAPE","TEXT","FRAME","CONNECTOR"],"default":"STICKY"},"x":{"type":"number","description":"Canvas x coordinate"},"y":{"type":"number","description":"Canvas y coordinate"},"width":{"type":"number","minimum":1,"maximum":10000},"height":{"type":"number","minimum":1,"maximum":10000},"text":{"type":"string","maxLength":10000},"color":{"type":"string","enum":["yellow","green","blue","pink","purple","orange","gray","white"],"description":"Palette slot name, not a hex value"},"style":{"type":"object","description":"Free-form style overrides stored on the item"},"featureId":{"type":"string"},"feedbackId":{"type":"string"}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"400":{"description":"Invalid request body, or unknown featureId/feedbackId for this organization"},"404":{"description":"Not found"}}}},"/okrs":{"get":{"summary":"List objectives with progress","security":[{"apiKey":[]}],"parameters":[{"name":"quarter","in":"query","schema":{"type":"string","example":"2026-Q3"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as ?cursor= to fetch the next page; null when exhausted"}}}}}}}}},"/events":{"post":{"summary":"Ingest product analytics events","description":"Accepts one event or a batch: `{\"events\": [...]}` (max 500 per request).","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"feature.used"},"userKey":{"type":"string"},"properties":{"type":"object"},"timestamp":{"type":"string","format":"date-time"}}}}}},"responses":{"202":{"description":"Accepted"}}}}}}