{"openapi":"3.1.0","info":{"title":"Taduu Public API","version":"1.0.0","description":"Programmatic access to your Taduu lists, tasks, notes, and\ninbox. Use a Personal Access Token from Settings →\nIntegrations and send it as a Bearer token.\n\nTwo paths for creating tasks:\n• `POST /api/v1/inbox` — text-only quick-capture into Unsorted\n• `POST /api/v1/tasks` — fully-defined task with list, priority, due date, etc.\n\nFor AI clients (Claude Desktop, claude.ai, Cursor), use the\nMCP server at https://taduu.com/mcp instead — same auth, same\nscopes, but exposed as native tools.","contact":{"name":"Taduu","url":"https://taduu.com"}},"servers":[{"url":"https://taduu.com","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"tdu_live_...","description":"Personal Access Token. Create one at Settings → Integrations on taduu.com."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"unauthorized"},"message":{"type":"string","example":"Missing Bearer token"}}}}},"Task":{"type":"object","properties":{"id":{"type":"string","example":"65f3a7..."},"taskId":{"type":"string","example":"ACT-001"},"listId":{"type":"string"},"workspaceId":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"notes":{"type":"string"},"status":{"type":"string","enum":["Not Started","Started","Ready for Review","In Review","Requires Revision","Reviewed","Complete","Blocked","Paused","Postponed","Ongoing","Deleted"]},"priority":{"type":"string","enum":["Low","Medium","High","Critical"]},"assignedTo":{"type":"string","nullable":true},"dueDate":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"estimatedDurationMinutes":{"type":"integer","nullable":true},"locationId":{"type":"string","nullable":true,"description":"Reference to a Location (/api/v1/locations) the task happens at. null when none. Calendar / day-planner views use this to compute drive time between consecutive items."},"externalRef":{"type":"string","nullable":true,"description":"External-system correlation id set by the integration that created the task (e.g. 'limitless-finances:txn:abc123'). Namespaced so multiple integrations co-exist. Filterable via GET /api/v1/tasks?externalRef=..."},"source":{"type":"string","nullable":true,"description":"Short string naming the recording system, e.g. 'limitless-finances'. null when the task was created in Taduu itself. Distinct from externalRef (which is the cross-system id)."},"completableBy":{"type":"string","enum":["anyone","external"],"description":"Completion authority. 'anyone' (default) — any path (web UI, API, MCP) can change the task's status. 'external' — the task is locked: the Taduu UI disables the status control with a lock icon, and only an API PATCH whose body source matches this task's source can change status. Use for execution tasks where completion must come from the system of record (e.g. Limitless Finances marks 'Pay Jane $2,140' complete only after the payment clears)."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"List":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"isPersonal":{"type":"boolean"},"isInbox":{"type":"boolean"},"visibility":{"type":"string","enum":["private","public","restricted"]},"listType":{"type":"string","nullable":true},"taskPrefix":{"type":"string"},"workspaceId":{"type":"string"},"ownerUserId":{"type":"string","nullable":true}}},"Note":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"category":{"type":"string"},"ownerUserId":{"type":"string"},"workspaceId":{"type":"string"},"sharedWithUserIds":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"source":{"type":"string","description":"Integration that created this note (e.g. 'inboxops' for a reply draft). Drives source-specific UI affordances like the 'Send via X' button."},"externalRef":{"type":"string","description":"Stable id from the sibling app — used by the by-external-ref endpoint so the integration can address the note without storing Taduu's Mongo _id."},"externalUrl":{"type":"string","format":"uri","description":"Deep link back to the source artefact (e.g. the original Gmail message the user is drafting a reply to)."},"externalSendAt":{"type":"string","format":"date-time","description":"Set when the user clicked 'Send via <source>' in the Taduu UI. The note stays visible with a 'Sent' badge until the sibling app confirms by hitting DELETE /api/v1/notes/by-external-ref/..."}}},"Workspace":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"isPersonal":{"type":"boolean"},"role":{"type":"string","enum":["owner","admin","member","guest"]}}},"User":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","nullable":true},"name":{"type":"string","nullable":true},"role":{"type":"string","enum":["owner","admin","member","guest"],"description":"Workspace-level role."},"engagementType":{"type":"string","enum":["employee","volunteer","contractor"],"nullable":true,"description":"Crew engagement type when the user is enrolled in this workspace's Crew. null when not enrolled. Used by integrations like Limitless Finances to map a Taduu user → a person in its Contributors ledger."}}},"InboxItem":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"notes":{"type":"string","nullable":true},"dueDate":{"type":"string","format":"date-time","nullable":true},"assignedTo":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"Location":{"type":"object","properties":{"id":{"type":"string","example":"65f3a7..."},"name":{"type":"string","example":"Studio — black backdrop"},"address":{"type":"string","nullable":true,"example":"1234 Industrial Way, Port Alberni, BC"},"lat":{"type":"number","nullable":true,"example":49.2336},"lng":{"type":"number","nullable":true,"example":-124.8055},"placeId":{"type":"string","nullable":true,"description":"Google Place ID. Set when the address was resolved via Places autocomplete OR the server-side geocode triggered by passing address without lat/lng."},"vibe":{"type":"string","nullable":true,"description":"Free-text description of the feel/look — e.g. 'dramatic, premium, golden-hour'."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags such as ['indoor', 'blue backdrop']. Lowercased + deduped server-side."},"kind":{"type":"string","nullable":true,"description":"What kind of place this is. Free string so integrations can extend with their own taxonomy. Suggested values: 'branch', 'website', 'studio', 'home', 'office'."},"url":{"type":"string","nullable":true,"description":"Optional URL for digital places (a bank website, a Zoom room). Filming/physical locations leave this null."},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TimeEntry":{"type":"object","properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"userId":{"type":"string","description":"Person the time is logged FOR."},"userEmail":{"type":"string","nullable":true,"description":"Email on the user the time is logged FOR. Integrations like Finances use this to attribute hours to a person record. null if the user has been removed."},"loggedByUserEmail":{"type":"string","nullable":true,"description":"Email on the person who recorded the entry (may differ from userEmail when a manager logs hours for a crew member)."},"taskId":{"type":"string","nullable":true,"description":"Action item id when the entry is pinned to a task; null for general admin time."},"workDate":{"type":"string","example":"2026-06-05","description":"YYYY-MM-DD bucket derived from startedAt (falls back to createdAt). Cheap for 'this week' rollups, no tz drift."},"startedAt":{"type":"string","format":"date-time","nullable":true},"endedAt":{"type":"string","format":"date-time","nullable":true},"minutes":{"type":"integer","description":"Source of truth. Not auto-recomputed from startedAt/endedAt."},"note":{"type":"string","nullable":true},"source":{"type":"string","nullable":true,"description":"Recording system name, e.g. 'limitless-finances'."},"externalRef":{"type":"string","nullable":true,"description":"External correlation id, e.g. 'limitless-finances:shift:abc123'."},"loggedByUserId":{"type":"string","description":"The person who recorded the entry (may differ from userId when a manager logs hours for crew)."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"WebhookSubscription":{"type":"object","properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"},"description":"Event types this subscription is interested in. Supported: 'task.created', 'task.updated', 'task.completed', 'task.reopened', 'task.deleted', 'time.created', 'time.updated', 'time.verified', 'time.deleted', or '*' for all events. `time.verified` fires after a contributor confirms a Claude-logged session at /verify-hours (and any minutes adjustment is reflected in the payload)."},"active":{"type":"boolean"},"description":{"type":"string","nullable":true},"format":{"type":"string","enum":["taduu-v1","limitless-finances"],"description":"Wire-format preset. 'taduu-v1' = enveloped {id, event, workspaceId, ..., data: <payload>} with 'X-Taduu-Signature: sha256=<hex>'. 'limitless-finances' = flat payload matching the Finances side contract with bare-hex signature. Default is 'taduu-v1'."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"lastDeliveryAt":{"type":"string","format":"date-time","nullable":true},"lastDeliveryStatus":{"type":"string","nullable":true,"enum":["delivered","failed","pending",null],"description":"Status of the most recent delivery attempt."}}}}},"paths":{"/api/v1/me":{"get":{"summary":"Identity probe","description":"Returns the token holder's user info, the scopes on this token, and the workspace it can reach. Every token has me:read so this also serves as a connectivity check.","tags":["Identity"],"responses":{"200":{"description":"Identity info.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","nullable":true},"name":{"type":"string","nullable":true},"firstName":{"type":"string","nullable":true}}},"token":{"type":"object","properties":{"scopes":{"type":"array","items":{"type":"string","enum":["me:read","workspaces:read","users:read","tasks:read","tasks:write","lists:read","lists:write","notes:read","notes:write","inbox:read","inbox:write","locations:read","locations:write","time:read","time:write","webhooks:read","webhooks:write"]}},"workspaceScope":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true}}}}}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/workspaces":{"get":{"summary":"List workspaces","description":"Workspaces this token can reach. A workspace-scoped token returns exactly one entry; an all-workspaces token returns every workspace the user is a member of.","tags":["Workspaces"],"responses":{"200":{"description":"Workspaces.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Workspace"}}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/users":{"get":{"summary":"List workspace members","description":"Workspace members the token can see, so an integration can resolve assignee-by-email to a real userId. Pass the email back as `assignedTo` in POST/PATCH /api/v1/tasks.","tags":["Workspaces"],"parameters":[{"name":"workspaceId","in":"query","required":false,"schema":{"type":"string"},"description":"Required for all-workspaces tokens to disambiguate; ignored for workspace-scoped tokens."}],"responses":{"200":{"description":"Members.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/lists":{"get":{"summary":"List accessible lists","tags":["Lists"],"parameters":[{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Lists.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/List"}}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"post":{"summary":"Create a list","tags":["Lists"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":80},"workspaceId":{"type":"string"}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/List"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A list with that name already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/lists/{id}":{"get":{"summary":"Get a list","tags":["Lists"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/List"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"patch":{"summary":"Rename a list (owner only)","tags":["Lists"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":80}}}}}},"responses":{"200":{"description":"Renamed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/List"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/tasks":{"get":{"summary":"Search tasks","tags":["Tasks"],"parameters":[{"name":"listId","in":"query","schema":{"type":"string"}},{"name":"workspaceId","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"assignee","in":"query","schema":{"type":"string"}},{"name":"dueBefore","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"dueAfter","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"completed","in":"query","schema":{"type":"boolean"}},{"name":"q","in":"query","schema":{"type":"string"}},{"name":"externalRef","in":"query","schema":{"type":"string"},"description":"Filter to the task(s) an integration pushed in. Match is exact — most integrations namespace as 'system:type:id'."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque cursor from a previous response's nextCursor."}],"responses":{"200":{"description":"Tasks.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Task"}},"nextCursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"post":{"summary":"Create a task (fully-defined)","description":"Creates an action item, OR upserts an existing one when externalRef matches an OPEN task in the workspace (Complete/Deleted rows are never reopened — a new task is created instead). For text-only quick capture without a target list, use POST /api/v1/inbox instead. Pass completedAt to back-date the task as already complete (lands in Complete status). When listId is omitted, the task lands in the workspace's Unsorted list (or the first accessible non-personal list if Unsorted isn't present). Integrations that match a different naming convention can use aliases: title → name, note → notes, externalId → externalRef. Native names win when both are sent. Upsert returns 200 with the updated task; fresh creates return 201.","tags":["Tasks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"workspaceId":{"type":"string","description":"Target workspace. Only meaningful when listId is omitted AND the token is 'all my workspaces' (per-workspace tokens always use their scoped workspace). If both workspaceId and listId are passed, they must match the list's workspace (400 otherwise)."},"listId":{"type":"string","description":"Optional. Resolution when omitted: (1) token's `defaultListId` if set AND no workspaceId override is passed; (2) Unsorted list of the resolved workspace; (3) first accessible non-personal list. Set a `defaultListId` on the token (Settings → Integrations → Developer) to keep an integration's pushes out of the shared workspace Unsorted."},"name":{"type":"string","maxLength":200},"title":{"type":"string","maxLength":200,"description":"Alias for `name`."},"notes":{"type":"string","maxLength":5000},"note":{"type":"string","maxLength":5000,"description":"Alias for `notes`."},"priority":{"type":"string","enum":["Low","Medium","High","Critical"],"default":"Medium"},"dueDate":{"type":"string","format":"date-time"},"assignedTo":{"type":"string","maxLength":500},"estimatedDurationMinutes":{"type":"integer","minimum":1,"maximum":10000},"completedAt":{"type":"string","format":"date-time"},"locationId":{"type":"string","description":"Optional Location id (/api/v1/locations)."},"externalRef":{"type":"string","maxLength":300,"description":"External-system correlation id. Namespace it ('system:type:id') so integrations don't collide. When set, the request acts as an UPSERT: if an open task with the same (workspace, externalRef) exists it's updated in place; if no match, a new task is created."},"externalId":{"type":"string","maxLength":300,"description":"Alias for `externalRef`."},"source":{"type":"string","maxLength":60,"description":"Short string naming the recording system, e.g. 'limitless-finances'. Stored on the task so the UI can badge integration-pushed rows. Required when completableBy='external'."},"completableBy":{"type":"string","enum":["anyone","external"],"default":"anyone","description":"Completion lock. 'external' makes the task uncompleteable from the Taduu UI — only an API caller whose request body source matches task.source can change its status. Requires `source` to be set on this POST so future status-change requests can be validated."}},"description":"Either `name` or `title` is required."}}}},"responses":{"200":{"description":"Existing task updated in place (returned when externalRef matched an OPEN task).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/tasks/{id}":{"get":{"summary":"Get a task","tags":["Tasks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"patch":{"summary":"Update a task","description":"Partial update — only the fields you pass are changed. Pass null on dueDate, assignedTo, or completedAt to clear them. For tasks with completableBy='external', changing status (or completedAt, or completableBy itself) requires passing `source` in the body matching the task's stored source — otherwise returns 403 completion_locked. The webhook fan-out fires the same task.completed / task.reopened event whether the change came from the UI or an API caller (idempotency contract — your handler may receive the event for completions YOU just initiated).","tags":["Tasks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"notes":{"type":"string","maxLength":5000},"status":{"type":"string","enum":["Not Started","Started","Ready for Review","In Review","Requires Revision","Reviewed","Complete","Blocked","Paused","Postponed","Ongoing","Deleted"]},"priority":{"type":"string","enum":["Low","Medium","High","Critical"]},"dueDate":{"type":"string","format":"date-time","nullable":true},"assignedTo":{"type":"string","maxLength":500,"nullable":true},"estimatedDurationMinutes":{"type":"integer","minimum":1,"maximum":10000,"nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"locationId":{"type":"string","nullable":true},"externalRef":{"type":"string","maxLength":300,"nullable":true},"source":{"type":"string","minLength":1,"maxLength":60,"description":"Source proof. Required when the task's completableBy is 'external' AND this PATCH changes status or completableBy — must equal the task's stored source."},"completableBy":{"type":"string","enum":["anyone","external"],"description":"Toggle the completion lock. Same source check applies — flipping a locked task back to 'anyone' requires the matching source."}}}}}},"responses":{"200":{"description":"Updated. May also be 403 with code 'completion_locked' if the task is completableBy='external' and the request didn't pass a matching source — see description.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"delete":{"summary":"Delete (soft) a task","description":"Soft-delete — status flips to 'Deleted'. The task is hidden from active views but preserved for audit / history. Tasks with completableBy='external' cannot be DELETEd here (DELETE has no body to carry the source proof) — use PATCH with `{status:'Deleted', source:'<task source>'}` to delete a locked task.","tags":["Tasks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/tasks/by-external-ref/{externalRef}":{"get":{"summary":"Fetch a task by externalRef","description":"Looks up a task by the externalRef the integration set on it — no need to know the Taduu Mongo id. Returns the task or 404 when no task with that externalRef exists in the resolved workspace.","tags":["Tasks"],"security":[{"bearerAuth":["tasks:read"]}],"parameters":[{"name":"externalRef","in":"path","required":true,"schema":{"type":"string"},"description":"The externalRef the integration set on the task (e.g. 'limitless-finances:bill:abc123'). May contain colons — URL-encode for safety."},{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"patch":{"summary":"Update a task by externalRef","description":"Same body, lock semantics, and webhook fan-out as PATCH /api/v1/tasks/{id} — just addresses the task by its externalRef instead of its Taduu id. The integration-friendly path for 'mark this Finances bill paid' calls: PATCH /api/v1/tasks/by-external-ref/limitless-finances:bill:abc with {status:'Complete', source:'limitless-finances'} closes the locked task in one round-trip.","tags":["Tasks"],"security":[{"bearerAuth":["tasks:write"]}],"parameters":[{"name":"externalRef","in":"path","required":true,"schema":{"type":"string"}},{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Same shape as PATCH /api/v1/tasks/{id} — see that endpoint for full field list."}}}},"responses":{"200":{"description":"Updated. May also be 403 with code 'completion_locked' — see PATCH /api/v1/tasks/{id} for the same semantics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"delete":{"summary":"Soft-delete a task by externalRef","description":"Same as DELETE /api/v1/tasks/{id} — flips status to 'Deleted'. Locked tasks (completableBy='external') can't be deleted via this route; use PATCH with body source.","tags":["Tasks"],"security":[{"bearerAuth":["tasks:write"]}],"parameters":[{"name":"externalRef","in":"path","required":true,"schema":{"type":"string"}},{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/inbox":{"post":{"summary":"Quick-capture into Unsorted","description":"The brain-dump path — text only. Use when you don't know which list it belongs in yet; the user will triage it later via the Define wizard.","tags":["Inbox"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":2000},"notes":{"type":"string","maxLength":5000},"dueDate":{"type":"string","format":"date-time"},"assignedTo":{"type":"string","maxLength":500}}}}}},"responses":{"201":{"description":"Captured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxItem"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/notes":{"get":{"summary":"List notes","tags":["Notes"],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Notes.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Note"}},"total":{"type":"integer"}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"post":{"summary":"Create a note","description":"Notes land in the owner's Personal workspace by default. Sharing is a separate flow. Integration notes (with `source` + `externalRef` set) are upserted: re-POSTing the same (source, externalRef) pair returns the existing note instead of creating a duplicate — safe to retry.","tags":["Notes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"body":{"type":"string","maxLength":50000},"category":{"type":"string","maxLength":80},"source":{"type":"string","maxLength":60,"description":"Tag this note as coming from a sibling app (e.g. 'inboxops'). Required when the Taduu UI should show a 'Send via <source>' button on the note."},"externalRef":{"type":"string","maxLength":300,"description":"Stable id from the sibling app. Combined with `source`, addresses the note via /api/v1/notes/by-external-ref/{ref}."},"externalUrl":{"type":"string","format":"uri","maxLength":500,"description":"Deep link back to the source artefact (e.g. the Gmail message URL the draft replies to). Rendered as 'View original in <source>' in the Notes editor."}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/notes/{id}":{"get":{"summary":"Get a note","tags":["Notes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"patch":{"summary":"Update a note (editor permission)","tags":["Notes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"body":{"type":"string","maxLength":50000},"category":{"type":"string","maxLength":80}}}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/notes/by-external-ref/{ref}":{"get":{"summary":"Get a note by externalRef","description":"Integration-friendly addressing — the sibling app doesn't store Taduu's Mongo _id; it looks the note up by the externalRef it set at create time. Source-scoped so two integrations can't collide on the same ref. `ref` must be URL-encoded.","tags":["Notes"],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded externalRef."},{"name":"source","in":"query","required":true,"schema":{"type":"string"},"description":"Source tag the note was created with. Required — disambiguates rows that share a ref string across different sibling apps."}],"responses":{"200":{"description":"Note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"delete":{"summary":"Delete a note by externalRef","description":"Used by sibling apps to confirm the side-effect is done — e.g. InboxOps deletes a draft note after the user actually sends the email. The Taduu UI shows a 'Sent via <source>' badge from the moment the user clicks the Send button; this DELETE makes the note disappear once the send is confirmed. Source-scoped like the GET.","tags":["Notes"],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded externalRef."},{"name":"source","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/locations":{"get":{"summary":"List the user's Locations","description":"Returns every Location owned by the token holder, newest first. Locations are personal reference data — places the user travels to or films at. Each Location carries optional lat/lng so calendar/day-planner views can compute drive time between consecutive items.","tags":["Locations"],"security":[{"bearerAuth":["locations:read"]}],"responses":{"200":{"description":"Locations list.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Location"}}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"post":{"summary":"Create a Location","description":"Required: name. If `address` is supplied without lat/lng, the server geocodes it via Google Places and fills lat/lng/placeId on the response. Explicit lat/lng skips the round-trip.","tags":["Locations"],"security":[{"bearerAuth":["locations:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"address":{"type":"string","maxLength":500,"nullable":true},"lat":{"type":"number","minimum":-90,"maximum":90,"nullable":true},"lng":{"type":"number","minimum":-180,"maximum":180,"nullable":true},"placeId":{"type":"string","maxLength":300,"nullable":true},"vibe":{"type":"string","maxLength":500,"nullable":true},"tags":{"type":"array","maxItems":30,"items":{"type":"string","maxLength":40}},"kind":{"type":"string","maxLength":40,"nullable":true,"description":"Free-string discriminator for what KIND of place this is. Suggested values: \"branch\", \"website\", \"studio\", \"home\", \"office\". Integrations can extend with their own taxonomy."},"url":{"type":"string","maxLength":500,"nullable":true,"description":"Optional URL for digital \"places\" (a bank website, a Zoom room)."},"notes":{"type":"string","maxLength":5000,"nullable":true}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/locations/{id}":{"get":{"summary":"Fetch a Location","tags":["Locations"],"security":[{"bearerAuth":["locations:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Location.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"patch":{"summary":"Update a Location","description":"Partial update. Pass only fields that should change. Setting `address` without lat/lng re-geocodes; explicit lat/lng skips the round-trip. Pass null on nullable fields to clear.","tags":["Locations"],"security":[{"bearerAuth":["locations:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"address":{"type":"string","maxLength":500,"nullable":true},"lat":{"type":"number","minimum":-90,"maximum":90,"nullable":true},"lng":{"type":"number","minimum":-180,"maximum":180,"nullable":true},"placeId":{"type":"string","maxLength":300,"nullable":true},"vibe":{"type":"string","maxLength":500,"nullable":true},"tags":{"type":"array","maxItems":30,"items":{"type":"string","maxLength":40}},"kind":{"type":"string","maxLength":40,"nullable":true},"url":{"type":"string","maxLength":500,"nullable":true},"notes":{"type":"string","maxLength":5000,"nullable":true}}}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"delete":{"summary":"Delete a Location","description":"Hard delete. Tasks that reference this location keep their locationId pointer (no cascade).","tags":["Locations"],"security":[{"bearerAuth":["locations:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/time":{"get":{"summary":"List time entries","description":"Returns discrete time entries inside the resolved workspace. Filter by userId, taskId, date range (`from`/`to` ISO timestamps OR cheap `fromWorkDate`/`toWorkDate` YYYY-MM-DD bounds), source, or externalRef. Sorted newest-first.","tags":["Time"],"security":[{"bearerAuth":["time:read"]}],"parameters":[{"name":"workspaceId","in":"query","schema":{"type":"string"}},{"name":"userId","in":"query","schema":{"type":"string"}},{"name":"taskId","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"fromWorkDate","in":"query","schema":{"type":"string","example":"2026-06-01"}},{"name":"toWorkDate","in":"query","schema":{"type":"string","example":"2026-06-07"}},{"name":"source","in":"query","schema":{"type":"string"}},{"name":"externalRef","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"Time entries page.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeEntry"}}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"post":{"summary":"Log a time entry","description":"Creates a discrete time entry. `minutes` is the source of truth; `startedAt`/`endedAt` are optional timer metadata and are NOT used to recompute minutes. Defaults the logged-for `userId` to the token holder. Pass another userId to log time FOR another person (e.g. a manager logging crew hours).","tags":["Time"],"security":[{"bearerAuth":["time:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["minutes"],"properties":{"workspaceId":{"type":"string"},"userId":{"type":"string"},"taskId":{"type":"string","nullable":true},"minutes":{"type":"integer","minimum":1,"maximum":1440},"startedAt":{"type":"string","format":"date-time","nullable":true},"endedAt":{"type":"string","format":"date-time","nullable":true},"note":{"type":"string","maxLength":2000,"nullable":true},"source":{"type":"string","maxLength":60,"nullable":true},"externalRef":{"type":"string","minLength":1,"maxLength":300,"nullable":true}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/time/{id}":{"get":{"summary":"Fetch a time entry","tags":["Time"],"security":[{"bearerAuth":["time:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Time entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"patch":{"summary":"Update a time entry","description":"Partial update. Pass only changed fields. Pass null on nullable fields to clear.","tags":["Time"],"security":[{"bearerAuth":["time:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string"},"taskId":{"type":"string","nullable":true},"minutes":{"type":"integer","minimum":1,"maximum":1440},"startedAt":{"type":"string","format":"date-time","nullable":true},"endedAt":{"type":"string","format":"date-time","nullable":true},"note":{"type":"string","maxLength":2000,"nullable":true},"source":{"type":"string","maxLength":60,"nullable":true},"externalRef":{"type":"string","minLength":1,"maxLength":300,"nullable":true}}}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"delete":{"summary":"Delete a time entry","description":"Hard delete.","tags":["Time"],"security":[{"bearerAuth":["time:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/webhooks":{"get":{"summary":"List webhook subscriptions","description":"Returns the webhook subscriptions registered in the resolved workspace. The shared secret is NEVER returned after create — store it from the POST response.","tags":["Webhooks"],"security":[{"bearerAuth":["webhooks:read"]}],"parameters":[{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Subscriptions list.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookSubscription"}}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"post":{"summary":"Create a webhook subscription","description":"Registers a new webhook subscription. The response includes the generated `secret` ONCE — store it; later reads of this subscription will not include the secret. Deliveries are signed with that secret using HMAC-SHA256 in the `X-Taduu-Signature` header (format: `sha256=<hex>`).","tags":["Webhooks"],"security":[{"bearerAuth":["webhooks:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"workspaceId":{"type":"string"},"url":{"type":"string","format":"uri","description":"HTTPS endpoint that will receive deliveries."},"events":{"type":"array","items":{"type":"string"},"description":"Event types — see WebhookSubscription.events."},"description":{"type":"string","maxLength":500,"nullable":true},"active":{"type":"boolean","default":true},"format":{"type":"string","enum":["taduu-v1","limitless-finances"],"default":"taduu-v1","description":"Wire-format preset. Default 'taduu-v1' = enveloped payload with 'X-Taduu-Signature: sha256=<hex>'. 'limitless-finances' = flat payload + bare-hex signature, matches the Limitless Finances contract byte-for-byte (task events without externalRef are dropped at enqueue time)."}}}}}},"responses":{"201":{"description":"Created. Response includes the shared `secret` ONCE.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookSubscription"},{"type":"object","properties":{"secret":{"type":"string","description":"Shared secret used to sign deliveries. Store it now — subsequent reads omit it."}}}]}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}},"/api/v1/webhooks/{id}":{"get":{"summary":"Fetch a webhook subscription","tags":["Webhooks"],"security":[{"bearerAuth":["webhooks:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"patch":{"summary":"Update a webhook subscription","description":"Partial update. Pass `rotateSecret: true` to generate a new shared secret — the response includes it ONCE.","tags":["Webhooks"],"security":[{"bearerAuth":["webhooks:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"description":{"type":"string","maxLength":500,"nullable":true},"active":{"type":"boolean"},"format":{"type":"string","enum":["taduu-v1","limitless-finances"]},"rotateSecret":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated. Includes `secret` only when rotateSecret was true.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}},"delete":{"summary":"Delete a webhook subscription","description":"Hard delete. Pending deliveries for this subscription are dropped.","tags":["Webhooks"],"security":[{"bearerAuth":["webhooks:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"workspaceId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"API access requires Pro. Token holder isn't on Pro (trial expired or not enrolled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found OR not visible to this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded. Default is 300 req/min per token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"x-ratelimit-limit":{"schema":{"type":"integer"}},"x-ratelimit-remaining":{"schema":{"type":"integer"}},"x-ratelimit-reset":{"schema":{"type":"integer"}}}}}}}}}