{"openapi":"3.1.1","info":{"title":"Doozy API","version":"1.0.0","summary":"Read and change everything in a Doozy workspace: todos, chats, agents and captures.","description":"The Doozy API gives a program the same reach a person has in the app.\nIt covers the four primitives Doozy is built on: **todos**, the work; **chats**, the conversations with agents; **agents**, the workers themselves; and **captures**, the recordings and notes the workspace remembers.\n\n## Authentication\n\nSend an API key as a bearer token:\n\n```\nAuthorization: Bearer doozy_sk_...\n```\n\nA key belongs to exactly one workspace. That is where every request lands, and there is no parameter to point it somewhere else.\n\n## Scopes\n\nEach key holds a fixed set of scopes, chosen when it is created. Capture content is the most sensitive data in a workspace, so `captures:read` stands on its own: a key can read every todo, chat and agent while remaining unable to read a single transcript.\n\n- `todos:read` — Read todos and todo lists, including their titles, descriptions, assignees, schedules and run history.\n- `todos:write` — Create, update, archive, restore and delete todos and todo lists, and start agent runs on a todo.\n- `chats:read` — Read chats and every message in them, including agent replies and the tool calls the agent made.\n- `chats:write` — Start chats, send messages, cancel a running chat, and archive, restore or delete chats.\n- `agents:read` — Read the agents in the workspace along with their instructions, skills and working hours.\n- `agents:write` — Create agents, change their instructions, permissions, skills and working hours, and archive or restore them.\n- `captures:read` — Read captures in full, including the transcript of a recording, the notes taken during it, and the generated summary.\n- `captures:write` — Create notes, start and stop recordings, edit capture titles, content and tags, and archive, restore or delete captures.\n\n## Pagination\n\nLists take `limit` and `cursor`. Read `nextCursor` off a response and pass it back as `cursor` to get the next page; `hasMore` tells you whether there is one. Cursors are opaque and keyset based, so a page stays correct while records are being created underneath it.\n\n## Errors\n\nEvery failure returns the same object, with a stable `code` to branch on and a `requestId` to quote if you get in touch.\n\n## Agent work is asynchronous\n\nSending a message to a chat starts an agent and returns immediately with a `run`. The reply arrives later. Poll `GET /chats/{chatId}/messages`, or pass `wait` on the send to hold the request open until the agent finishes.","contact":{"name":"Doozy support","email":"support@usedoozy.com"},"termsOfService":"https://usedoozy.com/terms"},"servers":[{"url":"https://api.usedoozy.com/api/v1","description":"Production"},{"url":"http://localhost:3333/api/v1","description":"Local development"}],"externalDocs":{"url":"https://usedoozy.com/docs/api","description":"Doozy API guides"},"tags":[{"name":"Meta","description":"Find the service, read the specification, and check what a credential can do."},{"name":"Todos","description":"The work in a workspace. Todos can be assigned to a person or to an agent, and an agent-assigned todo can be run."},{"name":"Todo lists","description":"The lists todos are filed under. Every workspace has a default list that new todos fall into."},{"name":"Chats","description":"Conversations with agents. Sending a message starts an agent and returns straight away; the reply arrives later."},{"name":"Agents","description":"The workers in a workspace, their standing instructions, their skills, and when they are on duty."},{"name":"Captures","description":"What the workspace has recorded and written down: meeting recordings with their transcripts, notes, and the summaries generated from them."},{"name":"API keys","description":"Create, list and revoke the credentials that open this API. Managed with a signed-in user session only, never with an API key."}],"security":[{"apiKey":[]}],"paths":{"/":{"get":{"operationId":"getServiceInfo","summary":"Get service information","description":"Confirm the API is reachable and find the specification. No credential needed.","tags":["Meta"],"security":[],"responses":{"200":{"description":"Service information.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceInfo"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiSpecification","summary":"Get the OpenAPI specification","description":"The full OpenAPI 3.1 description of this API, generated from the running server.\n\nIt is always current: the routes and this document are built from the same definitions, so a route that exists is described here and a route described here exists.","tags":["Meta"],"security":[],"responses":{"200":{"description":"An OpenAPI 3.1 document.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}}}}}},"/me":{"get":{"operationId":"getIdentity","summary":"Get the current identity","description":"Report which workspace this credential opens, who owns it, which scopes it holds, and every operation it may call.\n\nCall this first. It is the cheapest way to check that a key works, the way to learn a workspace id without one being configured anywhere, and the way to find out what you are allowed to do before attempting it: `allowedOperations` lists the operationIds this credential can reach, derived from the same scopes the router enforces.\n\nAn agent connecting to Doozy should start here, then read `getOpenApiSpecification` for the shape of the operations it just learned it can call.","tags":["Meta"],"security":[{"apiKey":[]},{"sessionToken":[]}],"responses":{"200":{"description":"The identity behind this request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Identity"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}}}},"/todos":{"get":{"operationId":"listTodos","summary":"List todos","description":"Page through the todos in the workspace, newest first by default.\n\nActive todos are returned. Pass `includeArchived=true` to see archived ones instead; there is no combined view, because a list that mixes live work with finished work is a list nobody can act on.\n\nSuggestions an agent has made but nobody has accepted are left out, unless you filter by `captureId`, where they are part of what that capture produced.","tags":["Todos"],"security":[{"apiKey":["todos:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"A page of todos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoCollection"}}}},"400":{"$ref":"#/components/responses/validation_failed","x-doozy-error-codes":["validation_failed","invalid_cursor"]},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records to return. Between 1 and 100; defaults to 25.","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from a previous page. Omit it to start from the beginning.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Only todos in this state.","schema":{"type":"string","enum":["ready","in_progress","done"]}},{"name":"priority","in":"query","required":false,"description":"Only todos at this priority.","schema":{"type":"string","enum":["urgent","high","medium","low"]}},{"name":"type","in":"query","required":false,"description":"Only tasks, or only responsibilities.","schema":{"type":"string","enum":["task","responsibility"]}},{"name":"todoListId","in":"query","required":false,"description":"Only todos in this list.","schema":{"type":"string","format":"uuid"}},{"name":"captureId","in":"query","required":false,"description":"Only todos that came from this capture.","schema":{"type":"string","format":"uuid"}},{"name":"assigneeId","in":"query","required":false,"description":"Only todos assigned to this user or agent.","schema":{"type":"string","format":"uuid"}},{"name":"includeArchived","in":"query","required":false,"description":"Set to `true` to list archived todos instead of active ones. Defaults to active.","schema":{"type":"string","enum":["true","false"]}},{"name":"query","in":"query","required":false,"description":"Free text match against the title and body.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"sort","in":"query","required":false,"description":"What to order by. Defaults to `createdAt`.","schema":{"type":"string","enum":["createdAt","updatedAt","dueDate","priority"]}},{"name":"order","in":"query","required":false,"description":"Which direction to order in. Defaults to `desc`.","schema":{"type":"string","enum":["asc","desc"]}}],"x-doozy-scopes":["todos:read"]},"post":{"operationId":"createTodo","summary":"Create a todo","description":"Add a piece of work to the workspace.\n\nGive a `title`, some `content`, or both. Without a `todoListId` the todo lands in the workspace default list.\n\nAssigning an agent starts that agent working on the todo immediately, which spends Doozy Minutes. Assign a person instead, or leave `assignees` off, if you only want the work recorded. `run: true` starts the agent explicitly and is the clearer way to ask for it.","tags":["Todos"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"201":{"description":"The todo that was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Todo"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"402":{"$ref":"#/components/responses/insufficient_minutes"},"403":{"$ref":"#/components/responses/missing_scope"},"409":{"$ref":"#/components/responses/idempotency_key_reused"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"The todo to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoCreateParams"}}}},"x-doozy-scopes":["todos:write"]}},"/todos/{todoId}":{"get":{"operationId":"getTodo","summary":"Get a todo","description":"Fetch one todo by id, including who it is assigned to and the most recent agent run on it.","tags":["Todos"],"security":[{"apiKey":["todos:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The todo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Todo"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoId","in":"path","required":true,"description":"The todo id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["todos:read"]},"patch":{"operationId":"updateTodo","summary":"Update a todo","description":"Change some of a todo. Fields you leave out keep their current values.\n\nSetting `status` to `done` completes the todo and closes any chats attached to it. Setting it back to `ready` reopens it.\n\nPassing `assignees` replaces the whole list. Adding an agent to that list starts the agent working, exactly as it does in the app.","tags":["Todos"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The todo as it now stands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Todo"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"402":{"$ref":"#/components/responses/insufficient_minutes"},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoId","in":"path","required":true,"description":"The todo id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The fields to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoUpdateParams"}}}},"x-doozy-scopes":["todos:write"]},"delete":{"operationId":"deleteTodo","summary":"Delete a todo","description":"Archive a todo. It disappears from the active list, stays readable at its id, and comes back with `restoreTodo`.\n\nPass `permanent=true` to erase it instead. That is final, and it is refused for a todo an agent has already run, because erasing it would orphan the record of that work.","tags":["Todos"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"Confirmation that the todo was archived or erased.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResource"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoId","in":"path","required":true,"description":"The todo id.","schema":{"type":"string","format":"uuid"}},{"name":"permanent","in":"query","required":false,"description":"Set to `true` to erase the todo instead of archiving it. Erasing cannot be undone, and a todo an agent has already run cannot be erased.","schema":{"type":"string","enum":["true","false"]}}],"x-doozy-scopes":["todos:write"]}},"/todos/{todoId}/restore":{"post":{"operationId":"restoreTodo","summary":"Restore an archived todo","description":"Bring an archived todo back into the active list. A todo that was erased cannot be restored.","tags":["Todos"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The restored todo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Todo"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoId","in":"path","required":true,"description":"The todo id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["todos:write"]}},"/todos/{todoId}/runs":{"post":{"operationId":"runTodo","summary":"Run a todo with an agent","description":"Put an agent to work on this todo.\n\nThe run starts in the background and this returns as soon as it has begun. The `chatId` on the response is where the work happens: read its messages to follow along, and watch the chat status to know when the agent has finished.\n\nA todo that is already running is refused. Agent work spends Doozy Minutes.","tags":["Todos"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"202":{"description":"The run that started. It is not finished yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoRun"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"402":{"$ref":"#/components/responses/insufficient_minutes"},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoId","in":"path","required":true,"description":"The todo id.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"Which agent to use, and what to tell it.","content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"description":"Which agent should do the work. Defaults to the agent already assigned to the todo.","type":"string","format":"uuid"},"message":{"description":"Extra instruction for this run. Defaults to the todo title and body.","type":"string","maxLength":15000}}}}}},"x-doozy-scopes":["todos:write"]},"get":{"operationId":"listTodoRuns","summary":"List runs on a todo","description":"Every attempt an agent has made at this todo, most recent first. Each run points at the chat where the work happened.","tags":["Todos"],"security":[{"apiKey":["todos:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The runs on this todo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoRunList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoId","in":"path","required":true,"description":"The todo id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["todos:read"]}},"/todo-lists":{"get":{"operationId":"listTodoLists","summary":"List todo lists","description":"Every list in the workspace, default first, each with a count of the todos filed under it. Workspaces have few lists, so this returns all of them in one page.","tags":["Todo lists"],"security":[{"apiKey":["todos:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The lists in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoListCollection"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"x-doozy-scopes":["todos:read"]},"post":{"operationId":"createTodoList","summary":"Create a todo list","description":"Add a list to file todos under. New lists are ordinary lists; the default list is set once when a workspace is created.","tags":["Todo lists"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"201":{"description":"The list that was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"The list to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoListCreateParams"}}}},"x-doozy-scopes":["todos:write"]}},"/todo-lists/{todoListId}":{"get":{"operationId":"getTodoList","summary":"Get a todo list","description":"Fetch one list by id, with its todo counts.","tags":["Todo lists"],"security":[{"apiKey":["todos:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoListId","in":"path","required":true,"description":"The list id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["todos:read"]},"patch":{"operationId":"updateTodoList","summary":"Update a todo list","description":"Rename a list or change how it is labelled. Anything you leave out stays as it was.","tags":["Todo lists"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The list as it now stands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoListId","in":"path","required":true,"description":"The list id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The fields to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoListUpdateParams"}}}},"x-doozy-scopes":["todos:write"]},"delete":{"operationId":"deleteTodoList","summary":"Delete a todo list","description":"Remove a list.\n\nA list that still holds todos is refused, and so is the default list. Move the todos to another list first, with `updateTodo`.","tags":["Todo lists"],"security":[{"apiKey":["todos:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"Confirmation that the list was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResource"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"todoListId","in":"path","required":true,"description":"The list id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["todos:write"]}},"/chats":{"get":{"operationId":"listChats","summary":"List chats","description":"Page through the chats in the workspace, most recently active first. Active chats are returned; pass `includeArchived=true` for archived ones instead.","tags":["Chats"],"security":[{"apiKey":["chats:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"A page of chats.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatList"}}}},"400":{"$ref":"#/components/responses/validation_failed","x-doozy-error-codes":["validation_failed","invalid_cursor"]},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records to return. Between 1 and 100; defaults to 25.","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from a previous page. Omit it to start from the beginning.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Only chats in this state.","schema":{"type":"string","enum":["queued","running","awaiting_input","completed","failed","cancelled"]}},{"name":"agentId","in":"query","required":false,"description":"Only chats with this agent.","schema":{"type":"string","format":"uuid"}},{"name":"query","in":"query","required":false,"description":"Free text match against chat titles and subtitles.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"includeArchived","in":"query","required":false,"description":"Set to `true` to list archived chats instead of active ones.","schema":{"type":"string","enum":["true","false"]}}],"x-doozy-scopes":["chats:read"]},"post":{"operationId":"createChat","summary":"Start a chat with an agent","description":"Start a conversation and give the agent its first message.\n\nThe agent begins work immediately and this returns before the reply exists. Read `chat.status`: `running` means it is still going, `completed` means the turn is done, and `awaiting_input` means it stopped for a person to approve something.\n\nTo collect the reply, call `listMessages` with `afterSequence` set to 0 and keep the highest sequence you see. Pass `waitSeconds` to have this request hold open until the agent finishes instead.\n\nAgent work spends Doozy Minutes.","tags":["Chats"],"security":[{"apiKey":["chats:write"]},{"sessionToken":[]}],"responses":{"201":{"description":"The chat that was started. The agent is still working.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"402":{"$ref":"#/components/responses/insufficient_minutes"},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"The message that starts the chat.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCreateParams"}}}},"x-doozy-scopes":["chats:write"]}},"/chats/{chatId}":{"get":{"operationId":"getChat","summary":"Get a chat","description":"Fetch one chat by id. Read `status` to learn whether the agent is still working, and `messageCount` to see whether anything new has arrived.","tags":["Chats"],"security":[{"apiKey":["chats:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The chat.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"chatId","in":"path","required":true,"description":"The chat id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["chats:read"]},"patch":{"operationId":"updateChat","summary":"Update a chat","description":"Rename a chat. Titles are generated automatically from the first message, so this is for when the generated one is wrong.","tags":["Chats"],"security":[{"apiKey":["chats:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The chat as it now stands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"chatId","in":"path","required":true,"description":"The chat id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The fields to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatUpdateParams"}}}},"x-doozy-scopes":["chats:write"]},"delete":{"operationId":"deleteChat","summary":"Delete a chat","description":"Archive a chat. It leaves the active list, stays readable at its id, and comes back with `restoreChat`.\n\nPass `permanent=true` to erase the chat and every message in it. That is final, and the record of what the agent did goes with it.","tags":["Chats"],"security":[{"apiKey":["chats:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"Confirmation that the chat was archived or erased.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResource"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"chatId","in":"path","required":true,"description":"The chat id.","schema":{"type":"string","format":"uuid"}},{"name":"permanent","in":"query","required":false,"description":"Set to `true` to erase the chat and every message in it. That cannot be undone. The default archives it instead.","schema":{"type":"string","enum":["true","false"]}}],"x-doozy-scopes":["chats:write"]}},"/chats/{chatId}/restore":{"post":{"operationId":"restoreChat","summary":"Restore an archived chat","description":"Bring an archived chat back into the active list.","tags":["Chats"],"security":[{"apiKey":["chats:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The restored chat.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"chatId","in":"path","required":true,"description":"The chat id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["chats:write"]}},"/chats/{chatId}/cancel":{"post":{"operationId":"cancelChat","summary":"Stop a running agent","description":"Stop the agent mid-turn. Whatever it had already done stays in the chat.\n\nA cancelled chat can be picked up again by sending another message.","tags":["Chats"],"security":[{"apiKey":["chats:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The chat, now cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"chatId","in":"path","required":true,"description":"The chat id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["chats:write"]}},"/chats/{chatId}/messages":{"get":{"operationId":"listMessages","summary":"List messages in a chat","description":"Read a chat, oldest message first.\n\nThis is the poll path for agent replies. Keep the highest `sequence` you have seen and pass it as `afterSequence` to get only what has arrived since. When `hasMore` is false and the chat status is no longer `running`, you have everything.\n\nEach message carries the readable `text` and, in `blocks`, the tool calls the agent made and what came back from them.","tags":["Chats"],"security":[{"apiKey":["chats:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"A page of messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageList"}}}},"400":{"$ref":"#/components/responses/validation_failed","x-doozy-error-codes":["validation_failed","invalid_cursor"]},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"chatId","in":"path","required":true,"description":"The chat id.","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"How many records to return. Between 1 and 100; defaults to 25.","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from a previous page. Omit it to start from the beginning.","schema":{"type":"string"}},{"name":"afterSequence","in":"query","required":false,"description":"Only messages after this sequence number. This is how you poll: keep the highest sequence you have seen and ask for what came after it.","schema":{"type":"integer","minimum":0,"maximum":9007199254740991}}],"x-doozy-scopes":["chats:read"]},"post":{"operationId":"sendMessage","summary":"Send a message to a chat","description":"Say something to the agent and start another turn.\n\nThis returns as soon as the work has started, not when the reply exists. `messageSequence` is the sequence number of the message you just sent; call `listMessages` with `afterSequence` set to it to collect the reply.\n\nPass `waitSeconds` to hold this request open until the agent finishes. Whatever it produced comes back in `replies`. If the time runs out, `timedOut` is true, the agent keeps working, and polling picks up where the wait left off.\n\nA chat with an agent already mid-turn is refused. Cancel it first, or wait for the turn to end.\n\nAgent work spends Doozy Minutes.","tags":["Chats"],"security":[{"apiKey":["chats:write"]},{"sessionToken":[]}],"responses":{"202":{"description":"The work has started. The reply may or may not have arrived, depending on `waitSeconds`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRun"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"402":{"$ref":"#/components/responses/insufficient_minutes"},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"chatId","in":"path","required":true,"description":"The chat id.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"The message to send.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageCreateParams"}}}},"x-doozy-scopes":["chats:write"]}},"/agents":{"get":{"operationId":"listAgents","summary":"List agents","description":"Every agent in the workspace, newest first. Workspaces have few agents, so this returns all of them in one page. Use an agent id here to start a chat or to assign a todo.","tags":["Agents"],"security":[{"apiKey":["agents:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The agents in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"includeArchived","in":"query","required":false,"description":"Set to `true` to include archived agents in the list.","schema":{"type":"string","enum":["true","false"]}}],"x-doozy-scopes":["agents:read"]},"post":{"operationId":"createAgent","summary":"Create an agent","description":"Add an agent to the workspace.\n\nThe name has to be unique among active agents. `instructions` is the main thing worth setting: it is what the agent follows in every conversation.\n\nNew agents pause for approval before risky actions unless you say otherwise.","tags":["Agents"],"security":[{"apiKey":["agents:write"]},{"sessionToken":[]}],"responses":{"201":{"description":"The agent that was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"The agent to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentCreateParams"}}}},"x-doozy-scopes":["agents:write"]}},"/agents/{agentId}":{"get":{"operationId":"getAgent","summary":"Get an agent","description":"Fetch one agent by id, with its instructions, approval setting and working hours.","tags":["Agents"],"security":[{"apiKey":["agents:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["agents:read"]},"patch":{"operationId":"updateAgent","summary":"Update an agent","description":"Change how an agent behaves. Anything you leave out stays as it was.\n\nChanging `instructions` affects every conversation the agent has from now on, including ones already open. Turning `requiresApproval` off lets the agent act without checking with a person first.","tags":["Agents"],"security":[{"apiKey":["agents:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The agent as it now stands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The fields to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentUpdateParams"}}}},"x-doozy-scopes":["agents:write"]},"delete":{"operationId":"deleteAgent","summary":"Archive an agent","description":"Take an agent out of service. Its chats and the work it did stay where they are, and `restoreAgent` brings it back.\n\nAgents are never erased, because erasing one would break the record of everything it did. The workspace default agent cannot be archived.","tags":["Agents"],"security":[{"apiKey":["agents:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"Confirmation that the agent was archived.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResource"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["agents:write"]}},"/agents/{agentId}/restore":{"post":{"operationId":"restoreAgent","summary":"Restore an archived agent","description":"Put an archived agent back into service.","tags":["Agents"],"security":[{"apiKey":["agents:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The restored agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["agents:write"]}},"/agents/{agentId}/skills":{"get":{"operationId":"listAgentSkills","summary":"List an agent skills","description":"The named procedures this agent knows. Skills are how a workspace teaches an agent to do something the same way every time.","tags":["Agents"],"security":[{"apiKey":["agents:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The skills this agent has.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSkillList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["agents:read"]},"post":{"operationId":"createAgentSkill","summary":"Teach an agent a skill","description":"Add a named procedure to an agent. The agent reaches for it when the work matches, so the name and the instructions are worth writing carefully.","tags":["Agents"],"security":[{"apiKey":["agents:write"]},{"sessionToken":[]}],"responses":{"201":{"description":"The skill that was added.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSkill"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"The skill to add.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSkillCreateParams"}}}},"x-doozy-scopes":["agents:write"]}},"/agents/{agentId}/skills/{skillId}":{"get":{"operationId":"getAgentSkill","summary":"Get an agent skill","description":"Fetch one skill by id, with the instructions the agent follows for it.","tags":["Agents"],"security":[{"apiKey":["agents:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The skill.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSkill"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}},{"name":"skillId","in":"path","required":true,"description":"The skill id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["agents:read"]},"patch":{"operationId":"updateAgentSkill","summary":"Update an agent skill","description":"Rename a skill or rewrite its instructions.","tags":["Agents"],"security":[{"apiKey":["agents:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The skill as it now stands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSkill"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}},{"name":"skillId","in":"path","required":true,"description":"The skill id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The fields to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSkillUpdateParams"}}}},"x-doozy-scopes":["agents:write"]},"delete":{"operationId":"deleteAgentSkill","summary":"Archive an agent skill","description":"Take a skill away from an agent. It is archived rather than erased, so the record of work done with it stays intact.","tags":["Agents"],"security":[{"apiKey":["agents:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"Confirmation that the skill was archived.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResource"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"agentId","in":"path","required":true,"description":"The agent id.","schema":{"type":"string","format":"uuid"}},{"name":"skillId","in":"path","required":true,"description":"The skill id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["agents:write"]}},"/captures":{"get":{"operationId":"listCaptures","summary":"List captures","description":"Page through the captures in the workspace, newest first.\n\nThis returns each capture without its body. Transcripts and notes run long, and a page of twenty of them would be a page nobody could use. Fetch a capture with `getCapture` to read it.\n\nRecordings that are still running are included, with status `recording`.","tags":["Captures"],"security":[{"apiKey":["captures:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"A page of captures, without their bodies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureList"}}}},"400":{"$ref":"#/components/responses/validation_failed","x-doozy-error-codes":["validation_failed","invalid_cursor"]},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records to return. Between 1 and 100; defaults to 25.","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from a previous page. Omit it to start from the beginning.","schema":{"type":"string"}},{"name":"query","in":"query","required":false,"description":"Free text match against titles, bodies and summaries.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"tags","in":"query","required":false,"description":"Comma separated tags. A capture must carry all of them to match. Call `listTags` to see what exists.","schema":{"type":"string"}},{"name":"createdAfter","in":"query","required":false,"description":"Only captures made at or after this time.","schema":{"type":"string","format":"date-time"}},{"name":"createdBefore","in":"query","required":false,"description":"Only captures made at or before this time.","schema":{"type":"string","format":"date-time"}},{"name":"includeArchived","in":"query","required":false,"description":"Set to `true` to list archived captures instead of active ones.","schema":{"type":"string","enum":["true","false"]}}],"x-doozy-scopes":["captures:read"]},"post":{"operationId":"createCapture","summary":"Create a capture","description":"Record something in the workspace.\n\nA `note` is finished the moment it is created. Its summary and any todos it suggests are generated straight after, so fetch it again a few seconds later to see them.\n\nA `recording` opens a session and nothing more. Audio comes from a microphone and is streamed to Doozy over the workspace WebSocket by the app, the desktop client or the mobile client. Over this API you can open the session, watch it, and stop it, but you cannot supply the audio. Stop it with `stopCapture` when the recording is over.\n\nOpening a recording session checks that the workspace has Doozy Minutes left.\n\nThis answers with the capture but not its body. Writing to a capture is not a way to read one: the transcript, notes and content are behind `captures:read`, so fetch them with `getCapture` if your key holds it.","tags":["Captures"],"security":[{"apiKey":["captures:write"]},{"sessionToken":[]}],"responses":{"201":{"description":"The capture that was created, without its body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureWriteResult"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"402":{"$ref":"#/components/responses/insufficient_minutes"},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string of your choosing, at most 255 characters. Retrying with the same key returns the first response instead of creating a second resource. Keys are remembered for 24 hours.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"description":"The capture to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureCreateParams"}}}},"x-doozy-scopes":["captures:write"]}},"/captures/{captureId}":{"get":{"operationId":"getCapture","summary":"Get a capture","description":"Fetch one capture in full: the written body, the transcript of the recording, the notes taken alongside it, and the generated summary.\n\nFor a recording that is still being transcribed, `transcript` is null and `status` is `processing`. Check back rather than assuming the recording was silent.","tags":["Captures"],"security":[{"apiKey":["captures:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The capture, with its content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureWithContent"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"captureId","in":"path","required":true,"description":"The capture id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["captures:read"]},"patch":{"operationId":"updateCapture","summary":"Update a capture","description":"Change a capture title, its written body, the notes taken alongside it, or its tags. Anything you leave out stays as it was.\n\nThe transcript of a recording is not editable here. It is what the recording said, and rewriting it would make the record untrue. Put corrections in `notes` instead.\n\nThis answers with the capture but not its body. Writing to a capture is not a way to read one: the transcript, notes and content are behind `captures:read`, so fetch them with `getCapture` if your key holds it.","tags":["Captures"],"security":[{"apiKey":["captures:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The capture as it now stands, without its body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureWriteResult"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"captureId","in":"path","required":true,"description":"The capture id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The fields to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureUpdateParams"}}}},"x-doozy-scopes":["captures:write"]},"delete":{"operationId":"deleteCapture","summary":"Delete a capture","description":"Archive a capture. It leaves the active feed, stays readable at its id, and comes back with `restoreCapture`.\n\nPass `permanent=true` to erase it. The transcript, the notes and the audio go with it, and none of that can be recovered.","tags":["Captures"],"security":[{"apiKey":["captures:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"Confirmation that the capture was archived or erased.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResource"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"captureId","in":"path","required":true,"description":"The capture id.","schema":{"type":"string","format":"uuid"}},{"name":"permanent","in":"query","required":false,"description":"Set to `true` to erase the capture, its transcript and its audio. That cannot be undone. The default archives it instead.","schema":{"type":"string","enum":["true","false"]}}],"x-doozy-scopes":["captures:write"]}},"/captures/{captureId}/restore":{"post":{"operationId":"restoreCapture","summary":"Restore an archived capture","description":"Bring an archived capture back into the active feed.\n\nThis answers with the capture but not its body. Writing to a capture is not a way to read one: the transcript, notes and content are behind `captures:read`, so fetch them with `getCapture` if your key holds it.","tags":["Captures"],"security":[{"apiKey":["captures:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The restored capture, without its body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureWriteResult"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"captureId","in":"path","required":true,"description":"The capture id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["captures:write"]}},"/captures/{captureId}/stop":{"post":{"operationId":"stopCapture","summary":"Stop a recording","description":"Close a recording session.\n\nThe transcript is written as the audio arrives, so this does not wait for transcription. The capture moves to `processing` while its summary and suggested todos are generated, then to `completed`.\n\nA capture that is not a running recording is refused.\n\nThis answers with the capture but not its body. Writing to a capture is not a way to read one: the transcript, notes and content are behind `captures:read`, so fetch them with `getCapture` if your key holds it.","tags":["Captures"],"security":[{"apiKey":["captures:write"]},{"sessionToken":[]}],"responses":{"200":{"description":"The capture, now processing, without its body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureWriteResult"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"404":{"$ref":"#/components/responses/resource_not_found"},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"captureId","in":"path","required":true,"description":"The capture id.","schema":{"type":"string","format":"uuid"}}],"x-doozy-scopes":["captures:write"]}},"/tags":{"get":{"operationId":"listTags","summary":"List tags","description":"Every tag in use across the workspace. Read this before filtering captures by tag, so you filter on tags that exist rather than tags you guessed.","tags":["Captures"],"security":[{"apiKey":["captures:read"]},{"sessionToken":[]}],"responses":{"200":{"description":"The tags in use.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"x-doozy-scopes":["captures:read"]}},"/api-keys/scopes":{"get":{"operationId":"listScopes","summary":"List available scopes","description":"Every scope this API defines, with what each one exposes, plus the common combinations. Read this to build a key-creation screen without copying a list that will go out of date.","tags":["API keys"],"security":[],"responses":{"200":{"description":"The scope catalogue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScopeCatalog"}}}}}}},"/api-keys":{"get":{"operationId":"listApiKeys","summary":"List API keys","description":"The keys in a workspace, newest first. Secrets are never included; a key is identified by its prefix and last four characters.","tags":["API keys"],"security":[{"sessionToken":[]}],"responses":{"200":{"description":"The keys in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyList"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope","x-doozy-error-codes":["missing_scope","api_key_auth_required","workspace_access_denied"]},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"workspaceId","in":"query","required":true,"description":"The workspace whose keys to list. You must be a member of it.","schema":{"type":"string","format":"uuid"}},{"name":"includeRevoked","in":"query","required":false,"description":"Set to `true` to include revoked keys in the list.","schema":{"type":"string","enum":["true","false"]}}]},"post":{"operationId":"createApiKey","summary":"Create an API key","description":"Mint a key for a workspace.\n\nThe secret comes back once, in this response, and is never retrievable again. Doozy stores only a hash of it, so a lost key can be revoked but not recovered.\n\nGrant the narrowest set of scopes that does the job. `captures:read` is worth thinking about separately from the rest: it opens meeting transcripts and the notes taken during them.\n\nAny member of a workspace may create a key for it, and any member may revoke any of its keys.","tags":["API keys"],"security":[{"sessionToken":[]}],"responses":{"201":{"description":"The key, including its secret. This is the only time the secret appears.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedApiKey"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope","x-doozy-error-codes":["missing_scope","api_key_auth_required","workspace_access_denied"]},"409":{"$ref":"#/components/responses/resource_conflict"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"requestBody":{"required":true,"description":"The key to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateParams"}}}}}},"/api-keys/{apiKeyId}":{"get":{"operationId":"getApiKey","summary":"Get an API key","description":"Fetch one key by id, without its secret. Useful for checking when a key was last used before revoking it.","tags":["API keys"],"security":[{"sessionToken":[]}],"responses":{"200":{"description":"The key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope","x-doozy-error-codes":["missing_scope","api_key_auth_required"]},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"apiKeyId","in":"path","required":true,"description":"The key id.","schema":{"type":"string","format":"uuid"}}]},"delete":{"operationId":"revokeApiKey","summary":"Revoke an API key","description":"Stop a key working. This takes effect on the next request that uses it, with no grace period and no cache to wait out.\n\nRevoking is permanent. The key is not erased: it drops out of the default listing but is still there with `includeRevoked=true`, carrying what it was and when it stopped.","tags":["API keys"],"security":[{"sessionToken":[]}],"responses":{"200":{"description":"Confirmation that the key was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokedApiKey"}}}},"400":{"$ref":"#/components/responses/validation_failed"},"401":{"$ref":"#/components/responses/missing_credentials","x-doozy-error-codes":["missing_credentials","invalid_api_key"]},"403":{"$ref":"#/components/responses/missing_scope","x-doozy-error-codes":["missing_scope","api_key_auth_required"]},"404":{"$ref":"#/components/responses/resource_not_found"},"429":{"$ref":"#/components/responses/rate_limit_exceeded"},"500":{"$ref":"#/components/responses/internal_error"}},"parameters":[{"name":"apiKeyId","in":"path","required":true,"description":"The key id.","schema":{"type":"string","format":"uuid"}}]}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"doozy_sk","description":"A workspace API key, created in Doozy under Settings, API keys. Send it as `Authorization: Bearer doozy_sk_...`. The key names its own workspace."},"sessionToken":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A signed-in user session token, paired with an `X-Doozy-Workspace-Id` header. This is how the Doozy app itself calls the API. API keys cannot be managed with an API key, so key management accepts this scheme only."}},"schemas":{"Error":{"description":"The shape every Doozy API failure takes.","type":"object","properties":{"error":{"description":"Everything known about what went wrong.","type":"object","properties":{"type":{"description":"The broad category of failure. Use it to decide whether retrying could help.","type":"string","enum":["invalid_request_error","authentication_error","permission_error","not_found_error","conflict_error","rate_limit_error","api_error"]},"code":{"description":"The stable identifier for this failure. Branch on this, never on the message.","type":"string","enum":["missing_credentials","invalid_api_key","expired_api_key","invalid_session_token","missing_scope","workspace_access_denied","api_key_auth_required","validation_failed","invalid_cursor","unsupported_media_type","payload_too_large","resource_not_found","unknown_operation","idempotency_key_reused","idempotency_request_in_progress","resource_conflict","rate_limit_exceeded","insufficient_minutes","internal_error","upstream_timeout"]},"message":{"description":"A sentence explaining what went wrong, written for a person reading a log.","type":"string"},"param":{"description":"The field at fault, when one field is at fault.","anyOf":[{"type":"string"},{"type":"null"}]},"docsUrl":{"description":"Where this error code is documented.","type":"string"},"specUrl":{"description":"The full OpenAPI document, needing no credential. Every failure carries it so a caller that has lost its way can re-read the contract without having to find it.","type":"string"},"requestId":{"description":"Identifies this request in our logs. Quote it when you get in touch.","type":"string"}},"required":["type","code","message","param","docsUrl","specUrl","requestId"]}},"required":["error"]},"ServiceInfo":{"description":"What this service is and where to read about it.","type":"object","properties":{"object":{"description":"Always `service_info`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"service_info"},"name":{"description":"The name of this service.","type":"string","const":"Doozy API"},"version":{"description":"The version of this API surface.","type":"string"},"documentationUrl":{"description":"Where the guides live.","type":"string"},"openapiUrl":{"description":"Where the machine-readable specification lives.","type":"string"}},"required":["object","name","version","documentationUrl","openapiUrl"]},"OpenApiDocument":{"description":"An OpenAPI 3.1 document.","type":"object","properties":{"openapi":{"description":"The OpenAPI version, always 3.1.x.","type":"string"}},"required":["openapi"],"additionalProperties":{}},"Identity":{"description":"Who you are and where you are. Call this first to confirm a key works and to learn its workspace id.","type":"object","properties":{"object":{"description":"Always `identity`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"identity"},"workspace":{"description":"The workspace this credential opens. There is exactly one.","type":"object","properties":{"name":{"description":"The workspace name.","type":"string"}},"required":["id","name"]},"organizationId":{"description":"The organization the workspace belongs to, when it belongs to one.","anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"user":{"description":"The person behind the request: the key owner, or the signed-in user.","type":"object","properties":{"email":{"description":"The email on the account.","type":"string"},"name":{"description":"The name on the account.","type":"string"}},"required":["id","email","name"]},"credential":{"description":"The credential that authenticated this request.","type":"object","properties":{"type":{"description":"Which kind of credential authenticated this request.","type":"string","enum":["api_key","user_session"]},"name":{"description":"The label on the API key, when a key was used.","anyOf":[{"type":"string"},{"type":"null"}]},"scopes":{"description":"What this credential is allowed to do.","type":"array","items":{"type":"string","enum":["todos:read","todos:write","chats:read","chats:write","agents:read","agents:write","captures:read","captures:write"]}},"expiresAt":{"description":"When the key stops working, or null when it does not expire.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["type","name","scopes","expiresAt"]},"allowedOperations":{"description":"Every operationId this credential may call, worked out from its scopes. This is the answer to \"what can I do here\" without cross-referencing the specification, and it is what an agent should read before deciding which calls to attempt.","type":"array","items":{"type":"string"}}},"required":["object","workspace","organizationId","user","credential","allowedOperations"]},"Todo":{"description":"A piece of work in a workspace. Todos can be assigned to a person or to an agent, and an agent-assigned todo can be run.","type":"object","properties":{"object":{"description":"Always `todo`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"todo"},"title":{"description":"The short line that names the work. Null when the todo only has a body.","anyOf":[{"type":"string"},{"type":"null"}]},"content":{"description":"The body of the todo: the detail an agent or a person needs to act. Markdown is preserved as written.","anyOf":[{"type":"string"},{"type":"null"}]},"status":{"description":"`ready` means nobody has started, `in_progress` means work is under way, `done` means it is finished.","type":"string","enum":["ready","in_progress","done"]},"priority":{"description":"How urgent the work is, or null when nobody has said.","anyOf":[{"type":"string","enum":["urgent","high","medium","low"]},{"type":"null"}]},"type":{"description":"A `task` is finished once. A `responsibility` is standing work that recurs.","type":"string","enum":["task","responsibility"]},"todoListId":{"description":"The list this todo sits in.","type":"string","format":"uuid"},"dueDate":{"description":"The date the work is due, as YYYY-MM-DD, or null when there is no deadline.","anyOf":[{"description":"The date the work is due.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"assignees":{"description":"Everyone responsible for this todo. Empty when nobody is.","type":"array","items":{"$ref":"#/components/schemas/TodoAssignee"}},"captureId":{"description":"The capture this todo came out of, when it was created from one.","anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"isArchived":{"description":"True once the todo has been archived. Archived todos stay readable and can be restored.","type":"boolean"},"isSuggested":{"description":"True while this is a suggestion an agent made that nobody has accepted yet.","type":"boolean"},"source":{"description":"Who or what created this todo.","anyOf":[{"type":"string","enum":["user_created","agent_created","auto_suggested"]},{"type":"null"}]},"latestRun":{"description":"The most recent agent run on this todo, or null if an agent has never run it.","anyOf":[{"type":"object","properties":{"chatId":{"description":"The chat the agent worked in. Read it to see what the agent did.","type":"string","format":"uuid"},"status":{"description":"Where the run got to.","type":"string","enum":["running","completed","failed"]},"startedAt":{"description":"When the run began.","type":"string","format":"date-time"},"finishedAt":{"description":"When the run ended, or null while it is still going.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","chatId","status","startedAt","finishedAt"]},{"type":"null"}]},"createdAt":{"description":"When the todo was created.","type":"string","format":"date-time"},"updatedAt":{"description":"When the todo last changed.","type":"string","format":"date-time"}},"required":["object","id","title","content","status","priority","type","todoListId","dueDate","assignees","captureId","isArchived","isSuggested","source","latestRun","createdAt","updatedAt"]},"TodoAssignee":{"description":"Someone responsible for a todo: a workspace member or an agent.","type":"object","properties":{"type":{"description":"Whether this assignee is a person in the workspace or one of its agents. Assigning an agent is what lets the todo be run.","type":"string","enum":["user","agent"]},"name":{"description":"The display name of the person or agent, when it is known.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","name"]},"TodoCollection":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The todos on this page, newest first unless you asked for another order.","type":"array","items":{"$ref":"#/components/schemas/Todo"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"TodoCreateParams":{"description":"What a new todo needs. Give at least a title or some content.","type":"object","properties":{"title":{"description":"The short line that names the work. Give this or `content`, or both.","type":"string","minLength":1,"maxLength":2000},"content":{"description":"The detail behind the work. Everything an agent needs to act belongs here.","type":"string","maxLength":15000},"priority":{"description":"How urgent the work is. Left unset when omitted.","type":"string","enum":["urgent","high","medium","low"]},"type":{"description":"Defaults to `task`. Use `responsibility` for standing work.","type":"string","enum":["task","responsibility"]},"todoListId":{"description":"The list to file this under. Omit it and the todo goes to the workspace default list.","type":"string","format":"uuid"},"dueDate":{"description":"The date the work is due, as YYYY-MM-DD.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"assignees":{"description":"Who is responsible. Assign an agent to make the todo runnable. Defaults to the key owner when omitted.","maxItems":50,"type":"array","items":{"type":"object","properties":{"type":{"description":"Which of the two this id names.","type":"string","enum":["user","agent"]}},"required":["id","type"]}},"captureId":{"description":"Link this todo to the capture it came out of.","type":"string","format":"uuid"},"run":{"description":"Start an agent on this todo as soon as it is created. Requires an agent assignee and spends Doozy Minutes.","type":"boolean"}}},"TodoUpdateParams":{"description":"Fields to change. Anything you leave out stays as it was, so a partial update is safe.","type":"object","properties":{"title":{"description":"Replace the title.","anyOf":[{"type":"string","minLength":1,"maxLength":2000},{"type":"null"}]},"content":{"description":"Replace the body.","anyOf":[{"type":"string","maxLength":15000},{"type":"null"}]},"status":{"description":"Move the todo along. Setting `done` marks it complete.","type":"string","enum":["ready","in_progress","done"]},"priority":{"description":"Change the urgency, or pass null to clear it.","anyOf":[{"type":"string","enum":["urgent","high","medium","low"]},{"type":"null"}]},"type":{"description":"Switch between task and responsibility.","type":"string","enum":["task","responsibility"]},"todoListId":{"description":"Move the todo to another list.","type":"string","format":"uuid"},"dueDate":{"description":"Set or clear the deadline.","anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"assignees":{"description":"Replace the assignee list outright. Pass an empty array to unassign everyone.","maxItems":50,"type":"array","items":{"type":"object","properties":{"type":{"description":"Which of the two this id names.","type":"string","enum":["user","agent"]}},"required":["id","type"]}}}},"DeletedResource":{"description":"Confirmation that a resource was archived or erased.","type":"object","properties":{"object":{"description":"Always `deleted`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"deleted"},"deleted":{"description":"Always true. Present so a success can be told from an error at a glance.","type":"boolean","const":true},"recoverable":{"description":"True when the resource was archived and can be restored, false when it was erased for good.","type":"boolean"}},"required":["object","id","deleted","recoverable"]},"TodoRun":{"description":"One attempt by an agent at a todo. Runs are asynchronous: this record appears immediately and finishes later.","type":"object","properties":{"object":{"description":"Always `todo_run`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"todo_run"},"todoId":{"description":"The todo that was run.","type":"string","format":"uuid"},"chatId":{"description":"The chat the agent worked in. Read its messages to watch the work happen.","type":"string","format":"uuid"},"status":{"description":"Where the run got to.","type":"string","enum":["running","completed","failed"]},"startedAt":{"description":"When the run began.","type":"string","format":"date-time"},"finishedAt":{"description":"When the run ended, or null while it is still going.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["object","id","todoId","chatId","status","startedAt","finishedAt"]},"TodoRunList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"Runs on this todo, most recent first.","type":"array","items":{"$ref":"#/components/schemas/TodoRun"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"TodoList":{"description":"A named list that todos are filed under.","type":"object","properties":{"object":{"description":"Always `todo_list`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"todo_list"},"name":{"description":"What the list is called.","type":"string"},"emoji":{"description":"An emoji shown beside the name, when one is set.","anyOf":[{"type":"string"},{"type":"null"}]},"color":{"description":"A colour label for the list, when one is set.","anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"description":"True for the one list a workspace files todos into when no list is named. Every workspace has exactly one, and it cannot be deleted.","type":"boolean"},"todoCount":{"description":"How many unarchived todos are filed here.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"activeTodoCount":{"description":"How many of those are still to do, rather than done.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"description":"When the list was created.","type":"string","format":"date-time"},"updatedAt":{"description":"When the list last changed.","type":"string","format":"date-time"}},"required":["object","id","name","emoji","color","isDefault","todoCount","activeTodoCount","createdAt","updatedAt"]},"TodoListCollection":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The lists in this workspace, default first.","type":"array","items":{"$ref":"#/components/schemas/TodoList"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"TodoListCreateParams":{"description":"A new list.","type":"object","properties":{"name":{"description":"What to call the list.","type":"string","minLength":1,"maxLength":120},"emoji":{"description":"An emoji to show beside the name.","type":"string","maxLength":8},"color":{"description":"A colour label for the list.","type":"string","maxLength":32}},"required":["name"]},"TodoListUpdateParams":{"description":"Fields to change. Anything you leave out stays as it was.","type":"object","properties":{"name":{"description":"Rename the list.","type":"string","minLength":1,"maxLength":120},"emoji":{"description":"Change or clear the emoji.","anyOf":[{"type":"string","maxLength":8},{"type":"null"}]},"color":{"description":"Change or clear the colour.","anyOf":[{"type":"string","maxLength":32},{"type":"null"}]}}},"Chat":{"description":"A conversation with an agent. Agents work asynchronously, so a chat is usually read more than once.","type":"object","properties":{"object":{"description":"Always `chat`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"chat"},"title":{"description":"A title generated from the first message. Null until the agent has written one, which happens shortly after a chat starts.","anyOf":[{"type":"string"},{"type":"null"}]},"subtitle":{"description":"A one-line summary of what the chat is about, when one has been generated.","anyOf":[{"type":"string"},{"type":"null"}]},"status":{"description":"`queued` and `running` mean the agent is working. `awaiting_input` means it stopped and needs a person, usually to approve a tool. `completed` means the turn finished. `failed` and `cancelled` speak for themselves.","type":"string","enum":["queued","running","awaiting_input","completed","failed","cancelled"]},"agentId":{"description":"The agent working in this chat, or null for a chat with the default assistant.","anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"todoId":{"description":"The todo this chat is doing the work for, when it is attached to one.","anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"messageCount":{"description":"How many messages the chat holds.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"errorMessage":{"description":"What went wrong, when the status is `failed`.","anyOf":[{"type":"string"},{"type":"null"}]},"isArchived":{"description":"True once the chat has been archived.","type":"boolean"},"createdAt":{"description":"When the chat was started.","type":"string","format":"date-time"},"lastMessageAt":{"description":"When the most recent message arrived.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"completedAt":{"description":"When the agent last finished a turn.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["object","id","title","subtitle","status","agentId","todoId","messageCount","errorMessage","isArchived","createdAt","lastMessageAt","completedAt"]},"ChatList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The chats on this page, most recently active first.","type":"array","items":{"$ref":"#/components/schemas/Chat"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"ChatCreateParams":{"description":"The message that starts a chat, and who to start it with.","type":"object","properties":{"message":{"description":"What to say to the agent. This starts the work.","type":"string","minLength":1,"maxLength":100000},"title":{"description":"A title for the chat. One is generated from your message if you leave this out.","type":"string","maxLength":200},"agentId":{"description":"Which agent to talk to. Omit it to use the workspace default assistant. List agents with `listAgents`.","type":"string","format":"uuid"},"todoId":{"description":"Attach this chat to a todo, so the work is recorded against it.","type":"string","format":"uuid"},"captureIds":{"description":"Captures to put in front of the agent as context. Their content is loaded into the conversation.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid"}},"timezone":{"description":"An IANA timezone name, for example `Europe/London`. The agent uses it to reason about dates. Defaults to UTC.","type":"string","maxLength":100},"waitSeconds":{"description":"Hold the request open for up to this many seconds, at most 120, waiting for the agent to finish, then return the chat as it stands. Omit it to return immediately.","type":"integer","minimum":1,"maximum":120}},"required":["message"]},"ChatUpdateParams":{"description":"Fields to change on a chat.","type":"object","properties":{"title":{"description":"Rename the chat.","type":"string","minLength":1,"maxLength":200}}},"Message":{"description":"One turn in a chat, from a person or from an agent.","type":"object","properties":{"object":{"description":"Always `message`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"message"},"chatId":{"description":"The chat this message belongs to.","type":"string","format":"uuid"},"role":{"description":"`user` for messages sent into the chat, `assistant` for the agent.","type":"string","enum":["user","assistant"]},"sequence":{"description":"Position in the chat, increasing over time. Pass the highest one you have seen as `afterSequence` to poll for what is new.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"text":{"description":"The readable text of the message, with every text block joined together. Empty when the turn was only tool work.","type":"string"},"blocks":{"description":"The message in full, including the agent tool calls and their results.","type":"array","items":{"$ref":"#/components/schemas/MessageBlock"}},"authorName":{"description":"Who wrote it, for messages a person sent.","anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"description":"When the message was recorded.","type":"string","format":"date-time"}},"required":["object","id","chatId","role","sequence","text","blocks","authorName","createdAt"]},"MessageBlock":{"description":"One part of a message. A single agent turn usually holds several: what it was thinking, what it called, what came back, and what it said.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"text"},"text":{"description":"What the agent or the person wrote.","type":"string"}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","const":"thinking"},"text":{"description":"The agent narrating its own reasoning as it works.","type":"string"}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","const":"tool_call"},"name":{"description":"The tool the agent invoked, for example `web_search`.","type":"string"},"input":{"description":"The arguments the agent passed. The shape depends on the tool.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type","id","name","input"]},{"type":"object","properties":{"type":{"type":"string","const":"tool_result"},"toolCallId":{"description":"The `tool_call` block this result answers.","type":"string"},"isError":{"description":"True when the tool failed.","type":"boolean"},"content":{"description":"What the tool returned, rendered as text.","type":"string"}},"required":["type","toolCallId","isError","content"]}]},"MessageList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The messages on this page, oldest first.","type":"array","items":{"$ref":"#/components/schemas/Message"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"ChatRun":{"description":"The result of starting agent work. Agent turns are asynchronous, so this describes work in flight rather than work done.","type":"object","properties":{"object":{"description":"Always `chat_run`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"chat_run"},"chatId":{"description":"The chat the agent is working in.","type":"string","format":"uuid"},"status":{"description":"Where the chat is now. `running` means the reply has not arrived yet.","type":"string","enum":["queued","running","awaiting_input","completed","failed","cancelled"]},"messageSequence":{"description":"The sequence number of the message you just sent. Poll `listMessages` with `afterSequence` set to this to collect the reply.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"replies":{"description":"Messages the agent produced while this request waited. Empty unless you passed `waitSeconds`, and possibly empty even then if the agent was still working when the wait ran out.","type":"array","items":{"$ref":"#/components/schemas/Message"}},"timedOut":{"description":"True when `waitSeconds` ran out before the agent finished. The work carries on; poll for the rest.","type":"boolean"}},"required":["object","chatId","status","messageSequence","replies","timedOut"]},"MessageCreateParams":{"description":"A message to send into an existing chat.","type":"object","properties":{"message":{"description":"What to say. This starts another agent turn.","type":"string","minLength":1,"maxLength":100000},"waitSeconds":{"description":"Hold the request open for up to this many seconds, at most 120, waiting for the reply, then return whatever has arrived. Omit it to return immediately.","type":"integer","minimum":1,"maximum":120}},"required":["message"]},"Agent":{"description":"A worker in a workspace, with its own instructions, permissions and skills.","type":"object","properties":{"object":{"description":"Always `agent`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"agent"},"name":{"description":"What the agent is called.","type":"string"},"description":{"description":"A short description of what this agent is for.","anyOf":[{"type":"string"},{"type":"null"}]},"instructions":{"description":"The standing instructions the agent follows in every conversation. This is the main lever on how it behaves.","anyOf":[{"type":"string"},{"type":"null"}]},"requiresApproval":{"description":"True when the agent pauses for a person before taking actions it judges risky. False lets it act without asking.","type":"boolean"},"approvalGuidance":{"description":"Extra guidance on what should and should not need approval.","anyOf":[{"type":"string"},{"type":"null"}]},"workingHoursEnabled":{"description":"True when the agent only works during set hours.","type":"boolean"},"workingHours":{"description":"The hours it works, when working hours are switched on.","anyOf":[{"$ref":"#/components/schemas/WorkingHours"},{"type":"null"}]},"profilePhotoUrl":{"description":"A link to the agent avatar. The link is temporary and expires.","anyOf":[{"type":"string"},{"type":"null"}]},"isArchived":{"description":"True once the agent has been archived.","type":"boolean"},"createdAt":{"description":"When the agent was created.","type":"string","format":"date-time"},"updatedAt":{"description":"When the agent last changed.","type":"string","format":"date-time"}},"required":["object","id","name","description","instructions","requiresApproval","approvalGuidance","workingHoursEnabled","workingHours","profilePhotoUrl","isArchived","createdAt","updatedAt"]},"WorkingHours":{"description":"When an agent is on duty. Outside these hours scheduled work waits rather than running.","type":"object","properties":{"workDays":{"description":"The days the agent works, as two-letter codes starting on Monday.","minItems":1,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"startHour":{"description":"The hour work starts, 0 to 23.","type":"integer","minimum":0,"maximum":23},"endHour":{"description":"The hour work ends, 0 to 23.","type":"integer","minimum":0,"maximum":23},"timezone":{"description":"An IANA timezone name, for example `America/New_York`.","type":"string","maxLength":100}},"required":["workDays","startHour","endHour","timezone"]},"AgentList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The agents in this workspace, newest first.","type":"array","items":{"$ref":"#/components/schemas/Agent"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"AgentCreateParams":{"description":"A new agent.","type":"object","properties":{"name":{"description":"What to call the agent. Names must be unique among active agents.","type":"string","minLength":1,"maxLength":100},"description":{"description":"A short description of what this agent is for.","type":"string","maxLength":1000},"instructions":{"description":"Standing instructions the agent follows in every conversation.","type":"string","maxLength":5000},"requiresApproval":{"description":"Whether the agent pauses for a person before risky actions. Defaults to true, which is the safe way round.","type":"boolean"},"approvalGuidance":{"description":"Extra guidance on what should and should not need approval.","type":"string","maxLength":10000}},"required":["name"]},"AgentUpdateParams":{"description":"Fields to change. Anything you leave out stays as it was.","type":"object","properties":{"name":{"description":"Rename the agent.","type":"string","minLength":1,"maxLength":100},"description":{"description":"Change the description.","anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"instructions":{"description":"Replace the standing instructions. This changes how the agent behaves everywhere.","anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"requiresApproval":{"description":"Switch the approval pause on or off.","type":"boolean"},"approvalGuidance":{"description":"Change the guidance on what needs approval.","anyOf":[{"type":"string","maxLength":10000},{"type":"null"}]},"workingHoursEnabled":{"description":"Switch working hours on or off.","type":"boolean"},"workingHours":{"description":"Set the hours the agent works. Start must come before end.","$ref":"#/components/schemas/WorkingHours"}}},"AgentSkill":{"description":"A named procedure an agent knows. Skills are how a workspace teaches an agent to do something the same way every time.","type":"object","properties":{"object":{"description":"Always `agent_skill`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"agent_skill"},"agentId":{"description":"The agent this skill belongs to.","type":"string","format":"uuid"},"name":{"description":"What the skill is called.","type":"string"},"instructions":{"description":"How the agent should carry out this skill.","anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"description":"A generated one-line summary of what the skill does.","anyOf":[{"type":"string"},{"type":"null"}]},"isArchived":{"description":"True once the skill has been archived.","type":"boolean"},"createdAt":{"description":"When the skill was created.","type":"string","format":"date-time"},"updatedAt":{"description":"When the skill last changed.","type":"string","format":"date-time"}},"required":["object","id","agentId","name","instructions","summary","isArchived","createdAt","updatedAt"]},"AgentSkillList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The skills this agent has.","type":"array","items":{"$ref":"#/components/schemas/AgentSkill"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"AgentSkillCreateParams":{"description":"A new skill for an agent.","type":"object","properties":{"name":{"description":"What to call the skill.","type":"string","minLength":1,"maxLength":200},"instructions":{"description":"How the agent should carry out this skill.","type":"string","maxLength":10000}},"required":["name"]},"AgentSkillUpdateParams":{"description":"Fields to change on a skill.","type":"object","properties":{"name":{"description":"Rename the skill.","type":"string","minLength":1,"maxLength":200},"instructions":{"description":"Replace the instructions.","anyOf":[{"type":"string","maxLength":10000},{"type":"null"}]}}},"Capture":{"description":"A capture without its body. Lists return this shape; fetch one capture to read the transcript and notes.","type":"object","properties":{"object":{"description":"Always `capture`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"capture"},"type":{"description":"`recording` when audio was captured, `note` when it was written.","type":"string","enum":["note","recording"]},"title":{"description":"The capture title, generated for recordings and taken from the first line of a note.","anyOf":[{"type":"string"},{"type":"null"}]},"subtitle":{"description":"A generated one-line description of what the capture is about.","anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"description":"The generated summary. Null until processing finishes, which for a recording takes a moment after it stops.","anyOf":[{"type":"string"},{"type":"null"}]},"status":{"description":"`recording` means audio is still arriving, `processing` means the transcript and summary are being made, `completed` means everything is there.","type":"string","enum":["recording","processing","completed","failed"]},"tags":{"description":"The tags on this capture.","type":"array","items":{"type":"string"}},"durationSeconds":{"description":"How long the recording ran, for recordings.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingId":{"description":"The recording session behind this capture, for recordings. An identifier only; the audio and its transcript are behind `captures:read`.","anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"isArchived":{"description":"True once the capture has been archived.","type":"boolean"},"createdAt":{"description":"When the capture was made.","type":"string","format":"date-time"},"updatedAt":{"description":"When it last changed.","type":"string","format":"date-time"}},"required":["object","id","type","title","subtitle","summary","status","tags","durationSeconds","recordingId","isArchived","createdAt","updatedAt"]},"CaptureList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The captures on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/Capture"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"CaptureWriteResult":{"description":"A capture after a change: enough to identify the record, and nothing that describes it. The title is written by the summariser from the transcript whenever nobody sets one, so it is withheld along with the transcript, the notes, the summary, the subtitle and the tags. Read any of them with `getCapture`, which needs `captures:read`.","type":"object","properties":{"object":{"description":"Always `capture`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"capture"},"type":{"description":"`recording` when audio was captured, `note` when it was written.","type":"string","enum":["note","recording"]},"status":{"description":"`recording` means audio is still arriving, `processing` means the transcript and summary are being made, `completed` means everything is there.","type":"string","enum":["recording","processing","completed","failed"]},"durationSeconds":{"description":"How long the recording ran, for recordings.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingId":{"description":"The recording session behind this capture, for recordings. An identifier only; the audio and its transcript are behind `captures:read`.","anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"isArchived":{"description":"True once the capture has been archived.","type":"boolean"},"createdAt":{"description":"When the capture was made.","type":"string","format":"date-time"},"updatedAt":{"description":"When it last changed.","type":"string","format":"date-time"}},"required":["object","id","type","status","durationSeconds","recordingId","isArchived","createdAt","updatedAt"]},"CaptureCreateParams":{"description":"A note, which is complete the moment it is written, or a recording session, which is opened here and filled by a microphone.","oneOf":[{"type":"object","properties":{"type":{"description":"Write something down.","type":"string","const":"note"},"content":{"description":"What to record. A leading markdown heading becomes the title and is taken out of the body.","type":"string","minLength":1,"maxLength":100000},"tags":{"description":"Tags to file it under.","maxItems":20,"type":"array","items":{"type":"string","maxLength":60}}},"required":["type","content"]},{"type":"object","properties":{"type":{"description":"Open a recording session, the same one the app opens when you press record.","type":"string","const":"recording"},"title":{"description":"A title for the recording.","type":"string","maxLength":200},"tags":{"description":"Tags to file it under.","maxItems":20,"type":"array","items":{"type":"string","maxLength":60}}},"required":["type"]}]},"CaptureWithContent":{"description":"A capture in full, including the transcript of a recording and the notes taken during it. Reading this needs the `captures:read` scope.","type":"object","properties":{"object":{"description":"Always `capture`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"capture"},"type":{"description":"`recording` when audio was captured, `note` when it was written.","type":"string","enum":["note","recording"]},"title":{"description":"The capture title, generated for recordings and taken from the first line of a note.","anyOf":[{"type":"string"},{"type":"null"}]},"subtitle":{"description":"A generated one-line description of what the capture is about.","anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"description":"The generated summary. Null until processing finishes, which for a recording takes a moment after it stops.","anyOf":[{"type":"string"},{"type":"null"}]},"status":{"description":"`recording` means audio is still arriving, `processing` means the transcript and summary are being made, `completed` means everything is there.","type":"string","enum":["recording","processing","completed","failed"]},"tags":{"description":"The tags on this capture.","type":"array","items":{"type":"string"}},"durationSeconds":{"description":"How long the recording ran, for recordings.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingId":{"description":"The recording session behind this capture, for recordings. An identifier only; the audio and its transcript are behind `captures:read`.","anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"isArchived":{"description":"True once the capture has been archived.","type":"boolean"},"createdAt":{"description":"When the capture was made.","type":"string","format":"date-time"},"updatedAt":{"description":"When it last changed.","type":"string","format":"date-time"},"content":{"description":"The written body of the capture. This is the note text for a note.","anyOf":[{"type":"string"},{"type":"null"}]},"transcript":{"description":"The transcript of the recording, with speaker labels where the audio allowed them. Null for a note, and null for a recording that is still being transcribed.","anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"description":"Notes typed alongside a recording while it was happening.","anyOf":[{"type":"string"},{"type":"null"}]},"mediaUrl":{"description":"A link to the audio file. The link is temporary and expires, so fetch it again rather than storing it.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","type","title","subtitle","summary","status","tags","durationSeconds","recordingId","isArchived","createdAt","updatedAt","content","transcript","notes","mediaUrl"]},"CaptureUpdateParams":{"description":"Fields to change. Anything you leave out stays as it was.","type":"object","properties":{"title":{"description":"Change the title.","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"content":{"description":"Replace the written body.","anyOf":[{"type":"string","maxLength":100000},{"type":"null"}]},"notes":{"description":"Replace the notes taken alongside a recording.","anyOf":[{"type":"string","maxLength":100000},{"type":"null"}]},"tags":{"description":"Replace the tag list outright. Pass an empty array to clear it.","maxItems":20,"type":"array","items":{"type":"string","maxLength":60}}}},"TagList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"Every tag in use in this workspace.","type":"array","items":{"type":"object","properties":{"object":{"description":"Always `tag`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"tag"},"name":{"description":"The tag, as it is stored.","type":"string"}},"required":["object","name"]}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"ScopeCatalog":{"description":"Every scope and the common combinations, so a key-creation interface can describe them without hardcoding a list that goes stale.","type":"object","properties":{"object":{"description":"Always `scope_catalog`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"scope_catalog"},"scopes":{"description":"Every scope this API defines.","type":"array","items":{"type":"object","properties":{"name":{"description":"The scope, as it is written on a key.","type":"string","enum":["todos:read","todos:write","chats:read","chats:write","agents:read","agents:write","captures:read","captures:write"]},"description":{"description":"What granting it lets a key do.","type":"string"}},"required":["name","description"]}},"presets":{"description":"Common combinations, offered as a starting point.","type":"array","items":{"type":"object","properties":{"name":{"description":"The preset identifier.","type":"string"},"label":{"description":"What to call it in an interface.","type":"string"},"description":{"description":"What the preset grants.","type":"string"},"scopes":{"description":"The scopes it expands to.","type":"array","items":{"type":"string","enum":["todos:read","todos:write","chats:read","chats:write","agents:read","agents:write","captures:read","captures:write"]}}},"required":["name","label","description","scopes"]}}},"required":["object","scopes","presets"]},"ApiKey":{"description":"A credential for this API, without its secret. The secret exists only in the response that created it.","type":"object","properties":{"object":{"description":"Always `api_key`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"api_key"},"name":{"description":"The label given to the key when it was created.","type":"string"},"prefix":{"description":"The start of the secret, enough to recognise the key without revealing it.","type":"string"},"last4":{"description":"The last four characters of the secret.","type":"string"},"scopes":{"description":"What this key is allowed to do. Fixed at creation.","type":"array","items":{"type":"string","enum":["todos:read","todos:write","chats:read","chats:write","agents:read","agents:write","captures:read","captures:write"]}},"workspaceId":{"description":"The workspace this key opens. A key opens exactly one.","type":"string","format":"uuid"},"rateLimitPerMinute":{"description":"How many requests a minute this key may make.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastUsedAt":{"description":"When the key was last used, recorded to the nearest minute. Null if it has never been used.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"expiresAt":{"description":"When the key stops working, or null if it does not expire.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"revokedAt":{"description":"When the key was revoked, or null while it still works.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"createdAt":{"description":"When the key was created.","type":"string","format":"date-time"}},"required":["object","id","name","prefix","last4","scopes","workspaceId","rateLimitPerMinute","lastUsedAt","expiresAt","revokedAt","createdAt"]},"ApiKeyList":{"type":"object","properties":{"object":{"description":"Always `list` for a paginated result.","type":"string","const":"list"},"data":{"description":"The keys in this workspace, newest first.","type":"array","items":{"$ref":"#/components/schemas/ApiKey"}},"hasMore":{"description":"True when another page is waiting behind this one.","type":"boolean"},"nextCursor":{"description":"Pass this back as `cursor` to fetch the next page. Null on the last page.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","hasMore","nextCursor"]},"CreatedApiKey":{"description":"A newly created key, including its secret. The secret is not stored and cannot be shown again.","type":"object","properties":{"object":{"description":"Always `api_key`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"api_key"},"name":{"description":"The label given to the key when it was created.","type":"string"},"prefix":{"description":"The start of the secret, enough to recognise the key without revealing it.","type":"string"},"last4":{"description":"The last four characters of the secret.","type":"string"},"scopes":{"description":"What this key is allowed to do. Fixed at creation.","type":"array","items":{"type":"string","enum":["todos:read","todos:write","chats:read","chats:write","agents:read","agents:write","captures:read","captures:write"]}},"workspaceId":{"description":"The workspace this key opens. A key opens exactly one.","type":"string","format":"uuid"},"rateLimitPerMinute":{"description":"How many requests a minute this key may make.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastUsedAt":{"description":"When the key was last used, recorded to the nearest minute. Null if it has never been used.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"expiresAt":{"description":"When the key stops working, or null if it does not expire.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"revokedAt":{"description":"When the key was revoked, or null while it still works.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"createdAt":{"description":"When the key was created.","type":"string","format":"date-time"},"secret":{"description":"The full key. This is the only time it is ever returned. Store it somewhere safe before you close the response; if you lose it, revoke the key and create another.","type":"string"}},"required":["object","id","name","prefix","last4","scopes","workspaceId","rateLimitPerMinute","lastUsedAt","expiresAt","revokedAt","createdAt","secret"]},"ApiKeyCreateParams":{"description":"A new key, and what it is allowed to do.","type":"object","properties":{"workspaceId":{"description":"The workspace this key will open. You must be a member of it.","type":"string","format":"uuid"},"name":{"description":"What this key is for, in words you will recognise in six months. \"Zapier production\" beats \"key 2\".","type":"string","minLength":1,"maxLength":120},"scopes":{"description":"What the key may do. Grant the least that works. `todos:read`: Read todos and todo lists, including their titles, descriptions, assignees, schedules and run history. `todos:write`: Create, update, archive, restore and delete todos and todo lists, and start agent runs on a todo. `chats:read`: Read chats and every message in them, including agent replies and the tool calls the agent made. `chats:write`: Start chats, send messages, cancel a running chat, and archive, restore or delete chats. `agents:read`: Read the agents in the workspace along with their instructions, skills and working hours. `agents:write`: Create agents, change their instructions, permissions, skills and working hours, and archive or restore them. `captures:read`: Read captures in full, including the transcript of a recording, the notes taken during it, and the generated summary. `captures:write`: Create notes, start and stop recordings, edit capture titles, content and tags, and archive, restore or delete captures.","minItems":1,"type":"array","items":{"type":"string","enum":["todos:read","todos:write","chats:read","chats:write","agents:read","agents:write","captures:read","captures:write"]}},"expiresInDays":{"description":"How many days until the key stops working. Omit it for a key that does not expire.","type":"integer","minimum":1,"maximum":3650}},"required":["workspaceId","name","scopes"]},"RevokedApiKey":{"description":"Confirmation that a key has been revoked.","type":"object","properties":{"object":{"description":"Always `api_key_revoked`. Every object this API returns names its own type, so a mixed list or a stored record can be told apart without context.","type":"string","const":"api_key_revoked"},"revokedAt":{"description":"When it was revoked. It stopped working at that moment.","type":"string","format":"date-time"}},"required":["object","id","revokedAt"]}},"responses":{"missing_credentials":{"description":"`missing_credentials` (401) — No credential was presented. Send an API key as `Authorization: Bearer doozy_sk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"invalid_api_key":{"description":"`invalid_api_key` (401) — The API key is malformed, unknown, or has been revoked. Mint a new key in workspace settings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"expired_api_key":{"description":"`expired_api_key` (401) — The API key passed its expiry date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"invalid_session_token":{"description":"`invalid_session_token` (401) — The signed-in user session token is invalid or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"missing_scope":{"description":"`missing_scope` (403) — The credential is valid but was not granted a scope this operation requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"workspace_access_denied":{"description":"`workspace_access_denied` (403) — The credential belongs to a different workspace, or the user is not a member of this one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"api_key_auth_required":{"description":"`api_key_auth_required` (403) — This operation is only available to a signed-in user. An API key cannot manage API keys.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"validation_failed":{"description":"`validation_failed` (400) — The request body, path or query failed validation. `param` names the first field at fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"invalid_cursor":{"description":"`invalid_cursor` (400) — The pagination cursor is not one this endpoint issued. Start the list again without a cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"unsupported_media_type":{"description":"`unsupported_media_type` (415) — The request body must be sent as `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"payload_too_large":{"description":"`payload_too_large` (413) — The request body exceeded the 500 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"resource_not_found":{"description":"`resource_not_found` (404) — No resource with that id exists in this workspace. Ids are workspace-scoped, so a valid id from another workspace reads as missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"unknown_operation":{"description":"`unknown_operation` (404) — No operation is mounted at this method and path.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"idempotency_key_reused":{"description":"`idempotency_key_reused` (409) — This `Idempotency-Key` was already used with a different request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"idempotency_request_in_progress":{"description":"`idempotency_request_in_progress` (409) — A request with this `Idempotency-Key` is still running. Retry once it finishes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"resource_conflict":{"description":"`resource_conflict` (409) — The resource is not in a state that allows this operation, for example sending to a chat that is mid-run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"rate_limit_exceeded":{"description":"`rate_limit_exceeded` (429) — The key exceeded its per-minute request budget. `Retry-After` gives the seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"insufficient_minutes":{"description":"`insufficient_minutes` (402) — The workspace is out of Doozy Minutes, so agent work cannot start.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"internal_error":{"description":"`internal_error` (500) — Something failed on our side. The request id identifies it in our logs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"upstream_timeout":{"description":"`upstream_timeout` (504) — A blocking wait ran past its deadline. The underlying work is still running; poll for the result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}