{"openapi":"3.0.0","paths":{"/v1/org/{org_id}/server":{"get":{"description":"`server.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nThe organization's machines. Each `id` is a `server_id` for creating an agent; pick one whose `status` is ONLINE.","operationId":"listServers","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListServerDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List servers","tags":["🖥️ Infrastructure / Servers"]},"post":{"description":"`server.create` — `OWNER` `ADMIN`\n\nReturns the provisioning token only once.","operationId":"createServer","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServerDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetServerDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Create server","tags":["🖥️ Infrastructure / Servers"]}},"/v1/org/{org_id}/server/{id}/regenerate-provisioning-token":{"post":{"description":"`server.edit` — `OWNER` `ADMIN`\n\nInvalidates the previous one.","operationId":"regenerateServerProvisioningToken","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetServerDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Regenerate provisioning token","tags":["🖥️ Infrastructure / Servers"]}},"/v1/org/{org_id}/approval":{"get":{"description":"`approval.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nAll approvals in the organization, most recent first.","operationId":"listApprovals","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"only_pending","required":true,"in":"query","schema":{"type":"boolean"}},{"name":"agent_id","required":false,"in":"query","schema":{"type":"number"}},{"name":"from","required":false,"in":"query","schema":{"type":"string"}},{"name":"to","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListApprovalDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List approvals","tags":["💬 Communication / Approvals"]}},"/v1/org/{org_id}/approval/{id}/resolve":{"patch":{"description":"`approval.resolve` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the approval as RESOLVED. The underlying issue (e.g. the OAuth token) must be fixed first — this only changes the status.","operationId":"resolveApproval","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetApprovalDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Resolve approval","tags":["💬 Communication / Approvals"]}},"/v1/org/{org_id}/approval/{id}/answer":{"patch":{"description":"`approval.resolve` — `OWNER` `ADMIN` `OPERATOR`\n\nAnswers a question (#308) by picking options and/or free text. The agent receives the answer as a turn in the thread it asked from.","operationId":"answerQuestion","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnswerQuestionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetApprovalDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Answer an agent question","tags":["💬 Communication / Approvals"]}},"/v1/org/{org_id}/approval/{id}/dismiss":{"patch":{"description":"`approval.resolve` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the approval as DISMISSED without acting on it. Use it when the request no longer applies (e.g. agent deleted).","operationId":"dismissApproval","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetApprovalDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Dismiss approval","tags":["💬 Communication / Approvals"]}},"/v1/org/{org_id}/agent/{agent_id}/conversation":{"get":{"description":"`agent.output.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"listConversations","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetConversationDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List agent conversations","tags":["💬 Communication / Conversations"]}},"/v1/org/{org_id}/agent/{agent_id}/conversation/{conversation_id}/message":{"get":{"description":"`agent.output.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nCursor-based pagination, scrolls upward.","operationId":"listMessages","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"conversation_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"before_seq","required":false,"in":"query","schema":{"type":"string"}},{"name":"after_seq","required":false,"in":"query","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMessageDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Paginated messages of a conversation","tags":["💬 Communication / Conversations"]}},"/v1/org/{org_id}/agent/{agent_id}/conversation/{conversation_id}/message/search":{"get":{"description":"`agent.output.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nSearch across a conversation's full history — returns the seq of matching messages.","operationId":"searchConversation","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"conversation_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"q","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Search the entire history","tags":["💬 Communication / Conversations"]}},"/v1/org/{org_id}/conversation":{"get":{"description":"`conversation.view` — `OWNER` `ADMIN`\n\nAll conversations of the organization — unified, filtered, and paginated view.","operationId":"listOrgConversations","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":false,"in":"query","description":"Exact conversation id (deep-link).","schema":{"minimum":1,"type":"number"}},{"name":"agent_id","required":false,"in":"query","description":"Filter by the owning agent id.","schema":{"minimum":1,"type":"number"}},{"name":"contact_id","required":false,"in":"query","description":"Filter by contact id.","schema":{"minimum":1,"type":"number"}},{"name":"channel_id","required":false,"in":"query","description":"Filter by a specific channel id.","schema":{"minimum":1,"type":"number"}},{"name":"transport","required":false,"in":"query","description":"Filter by channel transport (TELEGRAM, GMAIL, DISCORD…).","schema":{"minLength":1,"maxLength":32,"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by conversation status (OPEN, PENDING, RESOLVED, ARCHIVED).","schema":{"type":"string","enum":["OPEN","PENDING","RESOLVED","ARCHIVED"]}},{"name":"model","required":false,"in":"query","description":"Filter by the model last observed.","schema":{"minLength":1,"maxLength":120,"type":"string"}},{"name":"ref","required":false,"in":"query","description":"Opaque conversation ref (case-insensitive).","schema":{"minLength":1,"maxLength":40,"type":"string"}},{"name":"search","required":false,"in":"query","description":"Free-text search over the contact name + channel name.","schema":{"minLength":1,"maxLength":200,"type":"string"}},{"name":"sort","required":false,"in":"query","description":"Sort column: activity (last message), created (opened), contact (name), agent (name), channel (transport), model, status. Default: activity.","schema":{"type":"string","enum":["activity","created","contact","agent","channel","model","status"]}},{"name":"order","required":false,"in":"query","description":"Sort direction. Default: desc.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"limit","required":false,"in":"query","description":"Page size (1–200, default 50).","schema":{"minimum":1,"maximum":200,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Rows to skip (default 0).","schema":{"minimum":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationListPageDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List all conversations","tags":["💬 Communication / Conversations"]}},"/v1/org/{org_id}/agent":{"get":{"description":"`agent.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"listAgents","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List agents","tags":["🤖 Agents / Agents"]},"post":{"description":"`agent.create` — `OWNER` `ADMIN` `OPERATOR`\n\nCreated with STOPPED status until it's launched through the WS gateway.","operationId":"createAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Create agent","tags":["🤖 Agents / Agents"]}},"/v1/org/{org_id}/agent/{id}":{"get":{"description":"`agent.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"getAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Agent detail","tags":["🤖 Agents / Agents"]},"delete":{"description":"`agent.delete` — `OWNER` `ADMIN`\n\nOnly while it is STOPPED or in ERROR.","operationId":"deleteAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete agent","tags":["🤖 Agents / Agents"]},"patch":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"updateAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Edit agent metadata","tags":["🤖 Agents / Agents"]}},"/v1/org/{org_id}/agent/{id}/start":{"post":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nLaunches the agent's container on its server (returns instantly as SPAWNING).","operationId":"startAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Start agent","tags":["🤖 Agents / Agents"]}},"/v1/org/{org_id}/agent/{id}/stop":{"post":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nStops the agent's container (returns instantly as STOPPING).","operationId":"stopAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Stop agent","tags":["🤖 Agents / Agents"]}},"/v1/org/{org_id}/agent/{id}/pause":{"post":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nReturns instantly as PAUSING.","operationId":"pauseAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Pause agent","tags":["🤖 Agents / Agents"]}},"/v1/org/{org_id}/agent/{id}/resume":{"post":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nResumes the agent from PAUSED (returns instantly as RESUMING). Requires a confirmed email.","operationId":"resumeAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Resume paused agent","tags":["🤖 Agents / Agents"]}},"/v1/org/{org_id}/agent/{id}/reset":{"post":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nMoves an agent in ERROR back to STOPPED (no-op on healthy agents).","operationId":"resetAgent","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAgentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Clear agent error state","tags":["🤖 Agents / Agents"]}},"/v1/agent-image":{"get":{"description":"Only the available ones, unless the rest are explicitly requested. Global catalogue, no organization in the path, and needs no scope, so a service token can read it too. Each `id` is an `image_id` for creating an agent.","operationId":"listAgentImages","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"role_key","required":false,"in":"query","schema":{"type":"string"}},{"name":"include_unavailable","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentImageDto"}}}}},"security":[{"JWT":[]}],"summary":"🔒 List agent images","tags":["🖥️ Infrastructure / Agent images"]}},"/v1/org":{"get":{"description":"With a service token the list holds exactly one: the organization the token belongs to. Its `id` is the `org_id` every `/org/{org_id}/…` route needs — read it here instead of asking for it.","operationId":"listOrganizations","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrganizationDto"}}}}},"security":[{"JWT":[]}],"summary":"🔒 List my organizations","tags":["👤 Account & org / Organizations"]}},"/v1/org/{org_id}":{"get":{"description":"`organization.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nYou must be a member.","operationId":"getOrganization","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrganizationDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Organization detail","tags":["👤 Account & org / Organizations"]}},"/v1/org/{org_id}/agent/{agent_id}/connector/{connector_id}":{"post":{"description":"`connector.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nAssigns ONE connector to this agent without replacing the others (incremental, idempotent).","operationId":"addAgentConnector","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"connector_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Assign connector to agent","tags":["🔌 Resources / Connectors (agent shortcut)"]},"delete":{"description":"`connector.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nUnassigns ONE connector from this agent leaving the rest untouched (incremental, idempotent).","operationId":"removeAgentConnector","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"connector_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Unassign connector from agent","tags":["🔌 Resources / Connectors (agent shortcut)"]}},"/v1/org/{org_id}/memory":{"get":{"description":"`memory.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nOptionally filtered by scope / agent / orphaned.","operationId":"listMemories","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"scope","required":false,"in":"query","description":"Restrict to one scope","schema":{"type":"string","enum":["SHORT_TERM","LONG_TERM"]}},{"name":"scopes","required":false,"in":"query","description":"Memory scopes to keep (SHORT_TERM/LONG_TERM). Repeat or CSV. Wins over the legacy single-scope `scope` if both are sent.","schema":{"type":"array","items":{"type":"string","enum":["SHORT_TERM","LONG_TERM"]}}},{"name":"agent_id","required":false,"in":"query","description":"Restrict to memories assigned to this agent (handy for the per-agent view).","schema":{"minimum":1,"type":"number"}},{"name":"unassigned","required":false,"in":"query","description":"When true, only return memories with zero assignments (orphans). Default false.","schema":{"type":"boolean"}},{"name":"archived","required":false,"in":"query","description":"When true, return ONLY archived (soft-deleted) memories. Default false → live memories only. The two sets never mix; the trash view in the operator UI uses this flag.","schema":{"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Free-text search across name + description (case-insensitive substring).","schema":{"type":"string"}},{"name":"sort_by","required":false,"in":"query","description":"Sort column.","schema":{"type":"string","enum":["updated_at","name","created_at"]}},{"name":"sort_dir","required":false,"in":"query","description":"Sort direction.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"limit","required":false,"in":"query","description":"Page size (1-200). Default 200 (folder UI loads all).","schema":{"minimum":1,"maximum":200,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset (>= 0). Default 0.","schema":{"minimum":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMemoryDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List the organization's memories","tags":["🧩 Resources / Memories"]},"post":{"description":"`memory.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"createMemory","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMemoryDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMemoryWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Create memory","tags":["🧩 Resources / Memories"]}},"/v1/org/{org_id}/memory/{id}":{"get":{"description":"`memory.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nWith content and assignments.","operationId":"getMemory","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMemoryWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Memory detail","tags":["🧩 Resources / Memories"]},"delete":{"description":"`memory.delete` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the assigned agents to sync.","operationId":"deleteMemory","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete memory","tags":["🧩 Resources / Memories"]},"patch":{"description":"`memory.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the assigned agents to sync.","operationId":"updateMemory","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemoryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMemoryWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Edit memory","tags":["🧩 Resources / Memories"]}},"/v1/org/{org_id}/memory/{id}/agents":{"put":{"description":"`memory.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nSets the full list (diff of add+remove). Returns the memory with refreshed assignments.","operationId":"setMemoryAgents","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetMemoryAgentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMemoryWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Set the memory's agents","tags":["🧩 Resources / Memories"]}},"/v1/org/{org_id}/memory/{id}/archive":{"post":{"description":"`memory.delete` — `OWNER` `ADMIN` `OPERATOR`\n\nSoft delete: it disappears from listings and spawn payloads, but the assignment rows survive so unarchive can cleanly restore ownership.","operationId":"archiveMemory","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMemoryWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Archive memory","tags":["🧩 Resources / Memories"]}},"/v1/org/{org_id}/memory/{id}/unarchive":{"post":{"description":"`memory.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nAssigned agents regain access instantly.","operationId":"unarchiveMemory","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMemoryWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Restore memory","tags":["🧩 Resources / Memories"]}},"/v1/org/{org_id}/agent/{agent_id}/channel":{"get":{"description":"`agent.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"listChannels","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetChannelDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List the agent's external channels","tags":["💬 Communication / Channels"]}},"/v1/org/{org_id}/channel":{"get":{"description":"`agent.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nAll of the organization's external channels; optionally filtered by agent.","operationId":"listOrgChannels","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":false,"in":"query","description":"Restrict to channels of this agent (handy for the per-agent view).","schema":{"minimum":1,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetChannelDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List external channels","tags":["💬 Communication / Channels"]},"post":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nConnects an external channel (e.g. a Telegram bot) to an agent. Requires a confirmed email.","operationId":"createOrgChannel","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannelGlobalDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetChannelDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Connect external channel to an agent","tags":["💬 Communication / Channels"]}},"/v1/org/{org_id}/channel/{id}":{"get":{"description":"`agent.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"getOrgChannel","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetChannelDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Channel detail","tags":["💬 Communication / Channels"]},"delete":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"deleteOrgChannel","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Disconnect channel","tags":["💬 Communication / Channels"]},"patch":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nName, scope, token. Requires a confirmed email.","operationId":"updateOrgChannel","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChannelDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetChannelDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Edit channel","tags":["💬 Communication / Channels"]}},"/v1/org/{org_id}/channel/{id}/whitelist":{"post":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nAdds an origin id to the channel's inbound whitelist.","operationId":"addOrgChannelWhitelist","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddToWhitelistDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetChannelDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Add origin to the whitelist","tags":["💬 Communication / Channels"]}},"/v1/org/{org_id}/channel/{id}/whitelist/{origin_id}":{"delete":{"description":"`agent.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nRemoves an origin id from the channel's inbound whitelist.","operationId":"removeOrgChannelWhitelist","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"origin_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetChannelDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Remove origin from the whitelist","tags":["💬 Communication / Channels"]}},"/v1/transport":{"get":{"description":"","operationId":"listSupportedTransports","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"JWT":[]}],"summary":"🔒 Traffic direction of each transport","tags":["💬 Communication / Channels"]}},"/v1/org/{org_id}/cronjob":{"get":{"description":"`cronjob.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"listCronjobs","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"include_internal","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetCronjobDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List organization cronjobs","tags":["⏰ Automation / Scheduled jobs"]},"post":{"description":"`cronjob.create` — `OWNER` `ADMIN` `OPERATOR`\n\nRequires a confirmed email: a cronjob spends on its own schedule.","operationId":"createCronjob","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCronjobDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCronjobDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Create cronjob","tags":["⏰ Automation / Scheduled jobs"]}},"/v1/org/{org_id}/agent/{agent_id}/cronjob":{"get":{"description":"`cronjob.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"listAgentCronjobs","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"include_internal","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetCronjobDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List an agent's cronjobs","tags":["⏰ Automation / Scheduled jobs"]}},"/v1/org/{org_id}/cronjob/{id}":{"get":{"description":"`cronjob.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"getCronjob","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCronjobDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Cronjob details","tags":["⏰ Automation / Scheduled jobs"]},"delete":{"description":"`cronjob.delete` — `OWNER` `ADMIN` `OPERATOR`","operationId":"deleteCronjob","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete cronjob","tags":["⏰ Automation / Scheduled jobs"]},"patch":{"description":"`cronjob.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"updateCronjob","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCronjobDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCronjobDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Edit cronjob","tags":["⏰ Automation / Scheduled jobs"]}},"/v1/org/{org_id}/cronjob/{id}/runs":{"get":{"description":"`cronjob.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`","operationId":"listCronjobRuns","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronjobRunDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Cronjob run history","tags":["⏰ Automation / Scheduled jobs"]}},"/v1/org/{org_id}/cronjob/{id}/execute":{"post":{"description":"`cronjob.execute` — `OWNER` `ADMIN` `OPERATOR`\n\nRequires a confirmed email: triggers a turn that spends.","operationId":"executeCronjob","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"202":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Run cronjob now","tags":["⏰ Automation / Scheduled jobs"]}},"/v1/org/{org_id}/mcp":{"get":{"description":"`mcp.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nOptionally filtered by agent / orphaned / archived.","operationId":"listMcpServers","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":false,"in":"query","description":"Restrict to servers assigned to this agent (handy for the per-agent view).","schema":{"minimum":1,"type":"number"}},{"name":"unassigned","required":false,"in":"query","description":"When true, only return servers with zero assignments. Default false.","schema":{"type":"boolean"}},{"name":"archived","required":false,"in":"query","description":"When true, return ONLY archived (soft-deleted) servers. Default false → live only.","schema":{"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Free-text search across name + description (case-insensitive substring).","schema":{"type":"string"}},{"name":"transport","required":false,"in":"query","description":"Transport kind(s) to keep (STDIO / SSE / HTTP). Repeat the param or pass a CSV.","schema":{"type":"array","items":{"type":"string","enum":["STDIO","SSE","HTTP"]}}},{"name":"sort_by","required":false,"in":"query","description":"Sort column.","schema":{"type":"string","enum":["updated_at","name","created_at"]}},{"name":"sort_dir","required":false,"in":"query","description":"Sort direction.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"limit","required":false,"in":"query","description":"Page size (1-200). Default 50.","schema":{"minimum":1,"maximum":200,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset (>= 0). Default 0.","schema":{"minimum":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List MCP servers","tags":["🧩 Resources / MCP servers"]},"post":{"description":"`mcp.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"createMcpServer","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMcpWithAssignmentsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Register MCP server","tags":["🧩 Resources / MCP servers"]}},"/v1/org/{org_id}/mcp/{id}":{"get":{"description":"`mcp.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nIncludes its assignments.","operationId":"getMcpServer","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMcpWithAssignmentsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 MCP server details","tags":["🧩 Resources / MCP servers"]},"delete":{"description":"`mcp.delete` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the assigned agents for sync.","operationId":"deleteMcpServer","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete MCP server","tags":["🧩 Resources / MCP servers"]},"patch":{"description":"`mcp.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the assigned agents for sync.","operationId":"updateMcpServer","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMcpWithAssignmentsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Edit MCP server","tags":["🧩 Resources / MCP servers"]}},"/v1/org/{org_id}/mcp/{id}/agents":{"put":{"description":"`mcp.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nSets the full list (add+remove diff). Returns the server with refreshed assignments.","operationId":"setMcpServerAgents","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetMcpAgentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMcpWithAssignmentsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Set MCP server agents","tags":["🧩 Resources / MCP servers"]}},"/v1/org/{org_id}/mcp/{id}/archive":{"post":{"description":"`mcp.delete` — `OWNER` `ADMIN` `OPERATOR`\n\nSoft delete: disappears from listings and spawn payloads, but assignment rows survive so unarchive can cleanly restore membership.","operationId":"archiveMcpServer","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMcpWithAssignmentsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Archive MCP server","tags":["🧩 Resources / MCP servers"]}},"/v1/org/{org_id}/mcp/{id}/unarchive":{"post":{"description":"`mcp.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nAssigned agents regain access instantly.","operationId":"unarchiveMcpServer","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMcpWithAssignmentsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Restore MCP server","tags":["🧩 Resources / MCP servers"]}},"/v1/org/{org_id}/credential":{"get":{"description":"`credential.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nOptionally filtered by agent / orphaned / archived. Field VALUES are never returned.","operationId":"listCredentials","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":false,"in":"query","description":"Restrict to credentials assigned to this agent (per-agent view).","schema":{"minimum":1,"type":"number"}},{"name":"unassigned","required":false,"in":"query","description":"When true, only return credentials with zero assignments. Default false.","schema":{"type":"boolean"}},{"name":"archived","required":false,"in":"query","description":"When true, return ONLY archived (soft-deleted) credentials. Default false → live only.","schema":{"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Free-text search across name + description (case-insensitive substring).","schema":{"type":"string"}},{"name":"kind","required":false,"in":"query","description":"Free-form kind tag(s) to keep (e.g. \"login\", \"api-key\", \"ssh-key\"). Repeat the param or pass a CSV. Omit for any.","schema":{"type":"array","items":{"type":"string"}}},{"name":"sort_by","required":false,"in":"query","description":"Sort column.","schema":{"type":"string","enum":["updated_at","name","created_at"]}},{"name":"sort_dir","required":false,"in":"query","description":"Sort direction.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"limit","required":false,"in":"query","description":"Page size (1-200). Default 50.","schema":{"minimum":1,"maximum":200,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset (>= 0). Default 0.","schema":{"minimum":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCredentialDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List credentials","tags":["🧩 Resources / Credentials"]},"post":{"description":"`credential.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"createCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCredentialDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCredentialWithFieldsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Create credential","tags":["🧩 Resources / Credentials"]}},"/v1/org/{org_id}/credential/{id}":{"get":{"description":"`credential.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nField metadata (label + type, WITHOUT values) and assignments.","operationId":"getCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCredentialWithFieldsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Credential details","tags":["🧩 Resources / Credentials"]},"delete":{"description":"`credential.delete` — `OWNER` `ADMIN` `OPERATOR`","operationId":"deleteCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete credential","tags":["🧩 Resources / Credentials"]},"patch":{"description":"`credential.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nName / fields / type.","operationId":"updateCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCredentialDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCredentialWithFieldsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Edit credential","tags":["🧩 Resources / Credentials"]}},"/v1/org/{org_id}/credential/{id}/field/{field_id}/reveal":{"get":{"description":"`credential.reveal` — `OWNER` `ADMIN` `OPERATOR`\n\nDecrypts and returns the value of ONE field (for the operator's view/copy action). Gated on credential.reveal (separate from edit) — and, if set, the credential's operator ACL.","operationId":"revealCredentialField","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"field_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevealCredentialFieldDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Reveal a field value","tags":["🧩 Resources / Credentials"]}},"/v1/org/{org_id}/credential/{id}/agents":{"put":{"description":"`credential.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nSets the full list (add+remove diff).","operationId":"setCredentialAgents","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetCredentialAgentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCredentialWithFieldsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Set credential agents","tags":["🧩 Resources / Credentials"]}},"/v1/org/{org_id}/credential/{id}/archive":{"post":{"description":"`credential.delete` — `OWNER` `ADMIN` `OPERATOR`\n\nSoft delete: disappears from listings by default; assignment rows survive so unarchive can restore membership.","operationId":"archiveCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCredentialWithFieldsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Archive credential","tags":["🧩 Resources / Credentials"]}},"/v1/org/{org_id}/credential/{id}/unarchive":{"post":{"description":"`credential.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"unarchiveCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCredentialWithFieldsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Restore credential","tags":["🧩 Resources / Credentials"]}},"/v1/org/{org_id}/agent/{agent_id}/credential/{credential_id}":{"post":{"description":"`credential.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nAssigns ONE credential to this agent without replacing its other assignments (incremental, idempotent). Safe for wiring up service tokens — no read-modify-write of the full set.","operationId":"addAgentCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"credential_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Assign credential to agent","tags":["🧩 Resources / Credentials (agent shortcut)"]},"delete":{"description":"`credential.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nUnassigns ONE credential from this agent, leaving the rest intact (incremental, idempotent).","operationId":"removeAgentCredential","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"credential_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Unassign credential from agent","tags":["🧩 Resources / Credentials (agent shortcut)"]}},"/v1/org/{org_id}/skill":{"get":{"description":"`skill.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nOptionally filtered by agent / orphaned / archived.","operationId":"listSkills","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":false,"in":"query","description":"Restrict to skills assigned to this agent (handy for the per-agent view).","schema":{"minimum":1,"type":"number"}},{"name":"unassigned","required":false,"in":"query","description":"When true, only return skills with zero assignments. Default false.","schema":{"type":"boolean"}},{"name":"archived","required":false,"in":"query","description":"When true, return ONLY archived (soft-deleted) skills. Default false → live skills only.","schema":{"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Free-text search across name + description (case-insensitive substring).","schema":{"type":"string"}},{"name":"effort","required":false,"in":"query","description":"Per-skill effort overrides to keep (LOW/MEDIUM/HIGH/XHIGH/MAX). Repeat or CSV.","schema":{"type":"array","items":{"type":"string","enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"]}}},{"name":"sort_by","required":false,"in":"query","description":"Sort column.","schema":{"type":"string","enum":["updated_at","name","created_at"]}},{"name":"sort_dir","required":false,"in":"query","description":"Sort direction.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"limit","required":false,"in":"query","description":"Page size (1-200). Default 50.","schema":{"minimum":1,"maximum":200,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset (>= 0). Default 0.","schema":{"minimum":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List the organization's skills","tags":["🧩 Resources / Skills"]},"post":{"description":"`skill.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"createSkill","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Create skill","tags":["🧩 Resources / Skills"]}},"/v1/org/{org_id}/skill/{id}/entry":{"get":{"description":"`skill.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nThe files that travel next to SKILL.md. Without content.","operationId":"listSkillEntries","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetSkillEntryDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Skill files","tags":["🧩 Resources / Skills"]},"put":{"description":"`skill.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nCreates or replaces it, and re-seeds the agents that have the skill.","operationId":"putSkillEntry","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutSkillEntryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillEntryContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Write skill file","tags":["🧩 Resources / Skills"]},"delete":{"description":"`skill.edit` — `OWNER` `ADMIN` `OPERATOR`","operationId":"deleteSkillEntry","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"path","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete skill file","tags":["🧩 Resources / Skills"]}},"/v1/org/{org_id}/skill/{id}/entry/content":{"get":{"description":"`skill.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nOne file, with its content.","operationId":"getSkillEntry","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"path","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillEntryContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Skill file","tags":["🧩 Resources / Skills"]}},"/v1/org/{org_id}/skill/{id}":{"get":{"description":"`skill.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nWith content and assignments.","operationId":"getSkill","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Skill detail","tags":["🧩 Resources / Skills"]},"delete":{"description":"`skill.delete` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the assigned agents to sync.","operationId":"deleteSkill","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete skill","tags":["🧩 Resources / Skills"]},"patch":{"description":"`skill.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nMarks the assigned agents to sync.","operationId":"updateSkill","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Edit skill","tags":["🧩 Resources / Skills"]}},"/v1/org/{org_id}/skill/import":{"post":{"description":"`skill.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nBrings SKILL.md and its support files (#725 phase 3) as a new, unassigned skill — same guardrails as writing one by hand: the secret detector, size caps and versioning.","operationId":"importSkillFromGit","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportSkillFromGitDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportedSkillDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Import a skill from a github.com repo/folder","tags":["🧩 Resources / Skills"]}},"/v1/org/{org_id}/skill/{id}/agents":{"put":{"description":"`skill.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nSets the full list (diff of add+remove). Returns the skill with refreshed assignments.","operationId":"setSkillAgents","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSkillAgentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Set the skill's agents","tags":["🧩 Resources / Skills"]}},"/v1/org/{org_id}/skill/{id}/archive":{"post":{"description":"`skill.delete` — `OWNER` `ADMIN` `OPERATOR`\n\nSoft delete: it disappears from listings and spawn payloads, but the assignment rows survive so unarchive can cleanly restore ownership.","operationId":"archiveSkill","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Archive skill","tags":["🧩 Resources / Skills"]}},"/v1/org/{org_id}/skill/{id}/unarchive":{"post":{"description":"`skill.edit` — `OWNER` `ADMIN` `OPERATOR`\n\nAssigned agents regain access instantly.","operationId":"unarchiveSkill","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSkillWithContentDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Restore skill","tags":["🧩 Resources / Skills"]}},"/v1/model":{"get":{"description":"","operationId":"listModels","parameters":[{"name":"all","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetModelDto"}}}}}},"security":[{"JWT":[]}],"summary":"🔒 List global model catalog","tags":["🧬 Models"]}},"/v1/model/gateway/{provider}":{"get":{"description":"","operationId":"listGatewayModels","parameters":[{"name":"provider","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetGatewayModelDto"}}}}}},"security":[{"JWT":[]}],"summary":"🔒 List a gateway's models","tags":["🧬 Models"]}},"/v1/org/{org_id}/agent/{agent_id}/backup":{"get":{"description":"`backup.view` — `OWNER` `ADMIN`","operationId":"listAgentBackups","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetBackupDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List agent volume backups","tags":["🧩 Resources / Backups"]},"post":{"description":"`backup.manage` — `OWNER` `ADMIN`\n\nCopies the agent's /home volume to R2 (asynchronous — poll the list until COMPLETED).","operationId":"createAgentBackup","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetBackupDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Start agent volume backup","tags":["🧩 Resources / Backups"]}},"/v1/org/{org_id}/agent/{agent_id}/backup/{id}/restore":{"post":{"description":"`backup.manage` — `OWNER` `ADMIN`\n\nRestores a backup onto the agent's volume (DESTRUCTIVE — overwrites the current /home). Asynchronous.","operationId":"restoreAgentBackup","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetBackupDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Restore backup onto the volume","tags":["🧩 Resources / Backups"]}},"/v1/org/{org_id}/agent/{agent_id}/backup/{id}":{"delete":{"description":"`backup.manage` — `OWNER` `ADMIN`\n\nDeletes the R2 object and the row.","operationId":"deleteAgentBackup","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Delete backup","tags":["🧩 Resources / Backups"]}},"/v1/org/{org_id}/backup":{"get":{"description":"`backup.view` — `OWNER` `ADMIN`\n\nAll of the organization's backups.","operationId":"listOrgBackups","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetBackupDto"}}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List all backups","tags":["🧩 Resources / Backups"]}},"/v1/org/{org_id}/backup/unknown-objects":{"get":{"description":"`backup.manage` — `OWNER` `ADMIN`\n\nObjects that are in the organization's bucket and that no backup row claims. Read-only: nothing is deleted or adopted — the bucket belongs to someone else and we only look.","operationId":"listUnknownBackupObjects","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Unclaimed objects in the backup bucket","tags":["🧩 Resources / Backups"]}},"/v1/org/{org_id}/backup-destination":{"get":{"description":"`backup.view` — `OWNER` `ADMIN`\n\nThe bucket this organization writes its backups to, and whether backups are even happening. Never returns the secret key.","operationId":"getBackupDestination","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Organization backup destination","tags":["🧩 Resources / Backups"]},"put":{"description":"`backup.manage` — `OWNER` `ADMIN`\n\nPoints the organization at its own S3-compatible bucket. The destination is TESTED before saving (a test object is written and deleted); a bucket that can't be written to, or whose credential can't delete, is rejected with 400 instead of failing on the night the backup runs.","operationId":"setBackupDestination","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetBackupDestinationDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Configure own backup bucket","tags":["🧩 Resources / Backups"]},"delete":{"description":"`backup.manage` — `OWNER` `ADMIN`\n\nNothing is deleted from the client's bucket — new backups simply stop being made, and the existing ones can no longer be restored through us.","operationId":"removeBackupDestination","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Forget backup destination","tags":["🧩 Resources / Backups"]}},"/v1/org/{org_id}/audit":{"get":{"description":"`audit.view` — `OWNER` `ADMIN`\n\nAppend-only log of sensitive actions, most recent first. Filters: actor_kind, action, resource_type/id, date range. Paginated.","operationId":"listAudit","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"actor_kind","required":false,"in":"query","description":"Filter by actor kind.","schema":{"type":"string","enum":["HUMAN","AGENT","SERVICE","SYSTEM"]}},{"name":"action","required":false,"in":"query","description":"Filter by action (substring match, e.g. \"credential\").","schema":{"minLength":1,"maxLength":64,"type":"string"}},{"name":"resource_type","required":false,"in":"query","description":"Filter by resource type (e.g. \"credential\").","schema":{"minLength":1,"maxLength":32,"type":"string"}},{"name":"resource_id","required":false,"in":"query","description":"Filter by resource id.","schema":{"minimum":1,"type":"number"}},{"name":"agent_id","required":false,"in":"query","description":"Everything about one agent: actions ON it OR done BY it.","schema":{"minimum":1,"type":"number"}},{"name":"from","required":false,"in":"query","description":"Lower bound (ISO date) on created_at.","schema":{"type":"string"}},{"name":"to","required":false,"in":"query","description":"Upper bound (ISO date) on created_at.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size (1–200, default 50).","schema":{"minimum":1,"maximum":200,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset for pagination (default 0).","schema":{"minimum":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAuditDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List the organization's audit log","tags":["📊 Observability / Audit"]}},"/v1/org/{org_id}/agent/{agent_id}/logs":{"get":{"description":"`agent.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nMost recent first. Paginated (limit/offset); `from`/`to` (ISO dates) bound created_at.","operationId":"listAgentLogs","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"agent_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}},{"name":"from","required":false,"in":"query","schema":{"type":"string"}},{"name":"to","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAuditDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 An agent's audit feed","tags":["📊 Observability / Audit"]}},"/v1/org/{org_id}/billing":{"get":{"description":"`billing.view` — `OWNER` `ADMIN`\n\nOrganization totals (cost_micro + tokens) aggregated across all agents, with a per-agent breakdown.","operationId":"getBilling","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSummaryDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Live billing summary","tags":["📊 Observability / Billing"]}},"/v1/org/{org_id}/billing/agents":{"get":{"description":"`billing.view` — `OWNER` `ADMIN`\n\nHow many agents are paid for, how many exist, how low it can go, and what change is scheduled for renewal.","operationId":"getContractedAgents","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractedAgentsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Contracted agents and headroom","tags":["📊 Observability / Billing"]}},"/v1/org/{org_id}/cost-analytics":{"get":{"description":"`billing.view` — `OWNER` `ADMIN`\n\nCost report computed from per-message usage: totals, time series, and breakdown by agent/channel/transport/scope/conversation/contact/model, split by token type, with date windows and arbitrary filters.","operationId":"getCostAnalytics","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"from","required":false,"in":"query","description":"Lower bound (ISO date) on the message timestamp. Default: 30 days ago.","schema":{"type":"string"}},{"name":"to","required":false,"in":"query","description":"Upper bound (ISO date), exclusive. Default: now.","schema":{"type":"string"}},{"name":"bucket","required":false,"in":"query","description":"Time-bucket granularity of the series.","schema":{"type":"string","enum":["hour","day","week","month"]}},{"name":"group_by","required":false,"in":"query","description":"Dimension the breakdown is grouped by.","schema":{"type":"string","enum":["agent","channel","transport","scope","conversation","contact","model","cron"]}},{"name":"agent_id","required":false,"in":"query","description":"Filter to a single agent.","schema":{"minimum":1,"type":"number"}},{"name":"channel_id","required":false,"in":"query","description":"Filter to a single channel.","schema":{"minimum":1,"type":"number"}},{"name":"transport","required":false,"in":"query","description":"Filter to a single transport.","schema":{"type":"string","enum":["INTERNAL","WHATSAPP","GMAIL","DISCORD","TELEGRAM","SLACK","WEBHOOK","EMAIL","GITHUB","DRIVE","CALENDAR","HOST"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostAnalyticsDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Detailed cost report","tags":["📊 Observability / Billing"]}},"/v1/capability":{"get":{"description":"","operationId":"listCapabilities","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCapabilityDto"}}}}},"security":[{"JWT":[]}],"summary":"🔒 List global capability catalogue","tags":["🤖 Agents / Capabilities"]}},"/v1/org/{org_id}/inbox/contact":{"get":{"description":"`agent.output.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nInbox contacts grouped with their conversations.","operationId":"listInbox","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"scope","required":false,"in":"query","description":"mine = contacts where the authenticated user is the operator identity; all = every contact accessible in the org","schema":{"default":"all","type":"string","enum":["mine","all"]}},{"name":"status","required":false,"in":"query","description":"Filter conversations by status. ALL returns OPEN + CLOSED.","schema":{"default":"open","type":"string","enum":["open","pending","resolved","all"]}},{"name":"agent_id","required":false,"in":"query","description":"Restrict to a single agent","schema":{"minimum":1,"type":"number"}},{"name":"channel_id","required":false,"in":"query","description":"Restrict to a single channel","schema":{"minimum":1,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListInboxDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List Agent Desk contacts","tags":["💬 Communication / Inbox"]}},"/v1/org/{org_id}/inbox/contact/{contact_id}":{"get":{"description":"`agent.output.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nThe contact and all of its conversations.","operationId":"getInboxContact","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"contact_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetInboxContactDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Agent Desk contact detail","tags":["💬 Communication / Inbox"]}},"/v1/org/{org_id}/inbox/assignees":{"get":{"description":"`agent.input.send` — `OWNER` `ADMIN` `OPERATOR`\n\nCandidates for the Agent Desk selector (members + agents available for the Agent Desk).","operationId":"listInboxAssignees","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListInboxAssigneesDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List Agent Desk assignees","tags":["💬 Communication / Inbox"]}},"/v1/org/{org_id}/inbox/conversation/{conversation_id}/status":{"patch":{"description":"`agent.input.send` — `OWNER` `ADMIN` `OPERATOR`\n\nAgent Desk conversation: open / pending / resolved.","operationId":"setInboxConversationStatus","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"conversation_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetConversationStatusDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Change conversation status","tags":["💬 Communication / Inbox"]}},"/v1/org/{org_id}/inbox/contact/{contact_id}/assignee":{"patch":{"description":"`agent.input.send` — `OWNER` `ADMIN` `OPERATOR`\n\nSets or clears the Agent Desk assignee of an external contact.","operationId":"setInboxAssignee","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"contact_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAssigneeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetInboxContactDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Assign or release an Agent Desk contact","tags":["💬 Communication / Inbox"]}},"/v1/mcp-catalog":{"get":{"description":"","operationId":"listMcpCatalog","parameters":[{"name":"all","required":false,"in":"query","schema":{"type":"string"}},{"name":"i18n","required":false,"in":"query","schema":{"type":"string"}},{"name":"locale","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GetMcpCatalogDto"}}}}}},"security":[{"JWT":[]}],"summary":"🔒 List global MCP catalog","tags":["🔌 MCP Catalog"]}},"/v1/org/{org_id}/host":{"get":{"description":"`host.view` — `OWNER` `ADMIN` `OPERATOR` `VIEWER`\n\nMachines paired for consent-based remote support (kj-host).","operationId":"listHosts","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListHostDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 List hosts","tags":["🖥️ Infrastructure / Hosts"]},"post":{"description":"`host.create` — `OWNER` `ADMIN`\n\nReturns the provisioning token only once.","operationId":"createHost","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHostDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetHostDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Create host","tags":["🖥️ Infrastructure / Hosts"]}},"/v1/org/{org_id}/host/{id}/regenerate-provisioning-token":{"post":{"description":"`host.edit` — `OWNER` `ADMIN`\n\nInvalidates the previous one.","operationId":"regenerateHostProvisioningToken","parameters":[{"name":"org_id","required":true,"in":"path","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetHostDto"}}}}},"security":[{"bearer":[]},{"JWT":[]}],"summary":"🔒 Regenerate provisioning token","tags":["🖥️ Infrastructure / Hosts"]}}},"info":{"title":"Kujira API","description":"Control-plane API: organizations, agents, resources (skills, memories, MCP servers, credentials), communication (channels, inbox, approvals), scheduled jobs, audit and billing.\n\n## Authentication\n\nIntegrations authenticate with a **service token** on every request:\n\n```\nAuthorization: Bearer kjtk_live_…\n```\n\nThe token is created from the panel (**Settings → Service tokens**), belongs to **one** organization and carries its own permissions (scopes). The full secret is shown only once, at creation — store it in a secrets manager. It can be revoked at any time from the same panel.\n\n## Routes and organizations\n\nAll routes live under the `/v1` prefix. An organization's resources live under `/v1/org/{org_id}/…`: a token only sees its own organization — requesting another one's returns **404**, without revealing whether it exists.\n\nEach endpoint states the permission it requires (`resource.action`, e.g. `agent.view`). A token without that scope gets **403**.\n\n## Errors\n\nError responses share a common shape:\n\n```json\n{ \"status\": 403, \"code\": \"PERMISSION_DENIED\", \"message\": \"…\" }\n```\n\n`code` is stable and what you should branch on in code; `message` is a supporting text. Validation errors add an `errors` list with the per-field detail.\n\n## Rate limits\n\n60-second windows per IP: **600 requests** on any route as a general ceiling, with stricter quotas on sensitive surfaces (authentication **10/min**, public webhooks **120/min**, support **20/min**). Once a limit is exceeded, the API responds **429** with the `Retry-After` header.\n\n## More help\n\nPlatform guides and concepts: [docs.kujira.so](https://docs.kujira.so).","version":"0.1.0","contact":{}},"tags":[],"servers":[{"url":"https://api.kujira.so","description":"Production"}],"components":{"securitySchemes":{"bearer":{"name":"Service token","description":"Service token (`kjtk_live_…`), created from the panel under Settings → Service tokens. Belongs to one organization and carries its own permissions.","type":"http","scheme":"bearer"},"JWT":{"name":"JWT token","description":"A person's session in the panel. Not usable for integrations.","type":"http","scheme":"bearer"}},"schemas":{"GetServerDto":{"type":"object","properties":{"id":{"type":"number","description":"Server id","example":1},"organization_id":{"type":"number","description":"Organization id","example":1},"name":{"type":"string","description":"Display name","example":"hetzner-fra-01"},"description":{"type":"string","nullable":true,"description":"Free-form description"},"ip":{"type":"string","nullable":true,"description":"IPv4 or IPv6 address (auto-detected from the supervisor handshake)","example":"49.12.44.201"},"os":{"type":"string","nullable":true,"description":"Operating system label"},"cpu":{"type":"number","nullable":true,"description":"CPU cores"},"ram_mb":{"type":"number","nullable":true,"description":"RAM in MB"},"default_agent_memory_mb":{"type":"number","nullable":true,"description":"Default container RAM cap (MB) inherited by this server’s agents. Null = no limit.","example":4096},"default_agent_cpu":{"type":"number","nullable":true,"description":"Default container CPU cap (cores) inherited by this server’s agents. Null = no limit.","example":2},"status":{"enum":["UNPROVISIONED","ONLINE","WARNING","OFFLINE"],"type":"string","description":"Lifecycle status","example":"UNPROVISIONED"},"load":{"type":"number","nullable":true,"description":"Load average (0..1) reported by the agent"},"cpu_percent":{"type":"number","nullable":true,"description":"Instantaneous CPU usage (0..100) reported by the agent"},"ram_percent":{"type":"number","nullable":true,"description":"RAM usage (0..100) reported by the agent"},"alerts_enabled":{"type":"boolean","description":"Whether the resource-alert watcher is active for this server (KUJI-136)","example":true},"alert_ram_pct":{"type":"number","nullable":true,"description":"RAM alert threshold (%). Overrides the org default; null = inherit (org default → 85).","example":85},"alert_cpu_pct":{"type":"number","nullable":true,"description":"CPU alert threshold (%). Overrides the org default; null = inherit (org default → 90).","example":90},"alert_load_factor":{"type":"number","nullable":true,"description":"Load alert factor (load > factor × cores). Overrides the org default; null = inherit (org default → 1.5).","example":1.5},"uptime_seconds":{"type":"number","nullable":true,"description":"Uptime in seconds reported by the agent"},"last_seen_at":{"format":"date-time","type":"string","nullable":true,"description":"Last heartbeat timestamp"},"provisioning_expires_at":{"format":"date-time","type":"string","nullable":true,"description":"Provisioning expires at"},"supervisor_outdated":{"type":"boolean","description":"Whether the supervisor runs a version BEHIND the platform target (same comparison the upgrade endpoint gates on). False when current or when the comparison is unknown.","example":false},"agents_count":{"type":"number","description":"Number of agents bound to this server","example":3},"has_ssh_key":{"type":"boolean","description":"Whether an SSH key has been generated for this server","example":true},"provisioning_token":{"type":"string","description":"Provisioning token (only at create/regenerate time)"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"}},"required":["id","organization_id","name","status","alerts_enabled","supervisor_outdated","agents_count","has_ssh_key","created_at","updated_at"]},"ListServerDto":{"type":"object","properties":{"data":{"description":"Items in the current page","type":"array","items":{"$ref":"#/components/schemas/GetServerDto"}},"total":{"type":"number","description":"Total number of items matching the query","example":42},"page":{"type":"number","description":"Current page (1-indexed)","example":1},"limit":{"type":"number","description":"Page size","example":20}},"required":["data","total","page","limit"]},"CreateServerDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Display name (unique within the org)","example":"hetzner-fra-01"},"description":{"type":"string","maxLength":500,"description":"Free-form description","example":"Main VPS in Frankfurt"},"ip":{"type":"string","description":"IPv4 or IPv6 address. Optional — auto-detected from the supervisor handshake on connect (and refreshed on every reconnect, so dynamic IPs stay current).","example":"49.12.44.201"},"os":{"type":"string","maxLength":80,"description":"Operating system label","example":"Debian 12"},"cpu":{"type":"number","minimum":1,"description":"CPU cores","example":8},"ram_mb":{"type":"number","minimum":1,"description":"RAM in MB","example":32768},"default_agent_memory_mb":{"type":"number","nullable":true,"minimum":64,"maximum":1048576,"description":"Default container RAM cap (MB) for this server’s agents. Null clears it (no limit).","example":4096},"default_agent_cpu":{"type":"number","nullable":true,"minimum":0.1,"maximum":256,"description":"Default container CPU cap (cores) for this server’s agents. Null clears it (no limit).","example":2},"alerts_enabled":{"type":"boolean","description":"Enable/disable the resource-alert watcher for this server.","example":true},"alert_ram_pct":{"type":"number","nullable":true,"minimum":1,"maximum":100,"description":"RAM alert threshold (%). Null clears the override (inherit org default).","example":85},"alert_cpu_pct":{"type":"number","nullable":true,"minimum":1,"maximum":100,"description":"CPU alert threshold (%). Null clears the override (inherit org default).","example":90},"alert_load_factor":{"type":"number","nullable":true,"minimum":0.1,"maximum":100,"description":"Load alert factor (load > factor × cores). Null clears the override (inherit org default).","example":1.5}},"required":["name"]},"GetApprovalDto":{"type":"object","properties":{"id":{"type":"number","description":"Approval id","example":1},"organization_id":{"type":"number","description":"Organization id","example":1},"agent_id":{"type":"number","description":"Agent id this approval belongs to","example":1},"kind":{"enum":["OAUTH_RENEWAL","ACTION_REQUEST","QUESTION"],"type":"string","description":"What kind of approval this is","example":"OAUTH_RENEWAL"},"status":{"enum":["PENDING","RESOLVED","DISMISSED","EXPIRED"],"type":"string","description":"Lifecycle state of the approval","example":"PENDING"},"metadata":{"type":"object","additionalProperties":true,"nullable":true,"description":"Kind-specific data (free-form JSON). OAUTH_RENEWAL leaves this null today; other kinds will pack amount/target/etc here."},"conversation_id":{"type":"number","nullable":true,"description":"The operator conversation the agent asked from (null = no thread context). Lets the panel render the approval as an inline card in that chat."},"expires_at":{"format":"date-time","type":"string","nullable":true,"description":"When this PENDING approval auto-expires (null = never)"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"resolved_at":{"format":"date-time","type":"string","nullable":true,"description":"When the approval was resolved (null while PENDING)"},"resolved_by":{"type":"number","nullable":true,"description":"User id that resolved or dismissed it","example":1}},"required":["id","organization_id","agent_id","kind","status","created_at"]},"ListApprovalDto":{"type":"object","properties":{"data":{"description":"Items in the current page","type":"array","items":{"$ref":"#/components/schemas/GetApprovalDto"}},"total":{"type":"number","description":"Total number of items matching the query","example":3},"page":{"type":"number","description":"Current page (1-indexed)","example":1},"limit":{"type":"number","description":"Page size","example":20}},"required":["data","total","page","limit"]},"AnswerQuestionDto":{"type":"object","properties":{"selected":{"maxItems":8,"description":"Chosen options as 0-based indices into metadata.options. A single-choice question keeps the first one. May be empty for a free-text answer.","example":[0],"type":"array","items":{"type":"number","minimum":0}},"free_text":{"type":"string","maxLength":2000,"description":"Free-text nuance or full answer (\"bórrala pero deja los volúmenes\").","example":"bórrala pero deja los volúmenes"}}},"ConversationConnectionDto":{"type":"object","properties":{"id":{"type":"number","description":"Connection id","example":7},"name":{"type":"string","description":"Connection name","example":"OpenRouter"},"provider":{"type":"string","description":"Provider key","example":"openrouter"},"model":{"type":"string","nullable":true,"description":"Model the connection carries, when it carries one (OpenRouter, Ollama).","example":"deepseek/deepseek-v4-flash"}},"required":["id","name","provider","model"]},"ConversationContactDto":{"type":"object","properties":{"id":{"type":"number","description":"Contact id","example":1},"kind":{"type":"string","description":"Contact kind","example":"INTERNAL_USER"},"name":{"type":"string","description":"Contact display name","example":"Alice"},"user_id":{"type":"number","nullable":true,"description":"User id (internal_user only)"}},"required":["id","kind","name"]},"ConversationChannelDto":{"type":"object","properties":{"id":{"type":"number","description":"Channel id","example":1},"transport":{"type":"string","description":"Channel transport","example":"TELEGRAM"},"name":{"type":"string","description":"Channel display name","example":"Chat interno"}},"required":["id","transport","name"]},"GetConversationDto":{"type":"object","properties":{"id":{"type":"number","description":"Conversation id","example":1},"ref":{"type":"string","description":"Opaque public reference — paste it to jump to this conversation.","example":"MZROL9UC"},"contact_id":{"type":"number","description":"Contact id","example":1},"channel_id":{"type":"number","description":"Channel this thread lives on","example":1},"session_id":{"type":"string","description":"Claude session UUID for --resume","example":"a1b2c3d4-..."},"status":{"type":"string","description":"Status","example":"OPEN"},"model":{"type":"string","nullable":true,"description":"Last Claude model seen in this conversation (slug). Null until first reply.","example":"claude-haiku-4-5"},"model_override":{"type":"string","nullable":true,"description":"Operator/agent-set model override for this session (KJ-150). Null = inherit the agent default. Distinct from `model` (what last ran).","example":"claude-haiku-4-5"},"connection":{"nullable":true,"description":"Connection this conversation runs with when it is not the one of its agent. Null = the connection of the agent.","type":"object","allOf":[{"$ref":"#/components/schemas/ConversationConnectionDto"}]},"effort_override":{"type":"string","nullable":true,"description":"Reasoning effort set for this conversation (#277): LOW/MEDIUM/HIGH/XHIGH/MAX. Null = inherit the agent default.","example":"HIGH"},"is_operator_session":{"type":"boolean","description":"Whether this is an operator multi-session chat thread (KUJI-52).","example":true},"parent_conversation_id":{"type":"number","nullable":true,"description":"The session this one was opened from (#635): set when the agent split a job into parallel sessions with `session_create`. Null = opened on its own.","example":42},"title":{"type":"string","nullable":true,"description":"Session title for an operator session (\"Bug del login\"). Null = unnamed."},"icon":{"type":"string","nullable":true,"description":"Lucide icon name tagging the session (curated set). Null = default."},"color":{"type":"string","nullable":true,"description":"Theme palette color key tagging the session. Null = default."},"pinned":{"type":"boolean","description":"Pinned to the top of the operator session list."},"last_action":{"type":"string","nullable":true,"description":"Per-session last activity snippet (\"Ejecutando: …\"). Null until any."},"last_action_at":{"format":"date-time","type":"string","nullable":true,"description":"When last_action was recorded."},"contact":{"description":"Contact summary","allOf":[{"$ref":"#/components/schemas/ConversationContactDto"}]},"channel":{"description":"Channel summary (separates per-channel views)","allOf":[{"$ref":"#/components/schemas/ConversationChannelDto"}]},"context_tokens":{"type":"number","nullable":true,"description":"KUJI-87: live context size (input+cache tokens of the last turn). Null until the first result.","example":65000},"context_window":{"type":"number","description":"The model's context window (denominator of the saturation bar).","example":1000000},"reset_threshold":{"type":"number","nullable":true,"description":"Effective context cap (eje A) — marker for \"session compacts here\". Per-conversation override first, else the agent/org resolution. Null = no cap.","example":300000},"context_cap_tokens":{"type":"number","nullable":true,"description":"Per-conversation context-cap override. Null = inherit the agent/org cap; 0 = no cap for this conversation; >0 = compact at this many tokens.","example":500000},"opened_at":{"format":"date-time","type":"string","description":"Opened at"},"last_activity_at":{"format":"date-time","type":"string","description":"Last activity"},"debug_visible_until":{"format":"date-time","type":"string","nullable":true,"description":"Debug opt-in expiry. Future = exposed to admins/service for troubleshooting; null/past = private."},"support_session_at":{"format":"date-time","type":"string","nullable":true,"description":"When this thread was opened from a platform support visit (null = it was not). Such threads stay readable by the org owners and admins."}},"required":["id","ref","contact_id","channel_id","session_id","status","model","model_override","connection","effort_override","is_operator_session","parent_conversation_id","title","icon","color","pinned","last_action","last_action_at","contact","channel","context_window","opened_at","last_activity_at","debug_visible_until","support_session_at"]},"MessageDeliveryDto":{"type":"object","properties":{"status":{"type":"string","description":"PENDING | SENDING | SENT | FAILED | DRAFTED","example":"SENT"},"attempts":{"type":"number","description":"Delivery attempts so far","example":1},"error":{"type":"string","nullable":true,"description":"Last transport error, when it failed"},"sent_at":{"format":"date-time","type":"string","nullable":true,"description":"When the transport accepted it"}},"required":["status","attempts"]},"MessageAttachmentDto":{"type":"object","properties":{"id":{"type":"number","description":"Attachment id","example":42},"filename":{"type":"string","description":"Original filename","example":"report.csv"},"mime_type":{"type":"string","description":"MIME type","example":"image/png"},"size_bytes":{"type":"number","description":"Size in bytes","example":12345},"url":{"type":"string","description":"Backend proxy URL to stream the bytes (auth required).","example":"/org/2/attachment/42"},"uploaded_by_agent_id":{"type":"number","nullable":true,"description":"Agent that attached it (attachment_send), else null."}},"required":["id","filename","mime_type","size_bytes","url"]},"GetMessageDto":{"type":"object","properties":{"id":{"type":"number","description":"Message id","example":1},"conversation_id":{"type":"number","description":"Conversation id","example":1},"seq":{"type":"number","description":"Monotonic sequence within conversation","example":1},"role":{"type":"string","description":"Role","example":"ASSISTANT"},"kind":{"type":"string","description":"Kind","example":"TEXT"},"via_channel_id":{"type":"number","nullable":true,"description":"Channel the message arrived/left through"},"via_identity_id":{"type":"number","nullable":true,"description":"Identity that sent the message"},"author_user_id":{"type":"number","nullable":true,"description":"Human author (operator) user id. NULL for agent output and external contacts."},"author_name":{"type":"string","nullable":true,"description":"Author display name when author_user_id is set."},"status":{"type":"string","description":"DELIVERED or PENDING (auth failure / offline)","example":"DELIVERED"},"delivery":{"nullable":true,"description":"Delivery to the customer channel (Telegram, mail…) for messages that go out through one. NULL for everything else — internal threads, inbound messages. Distinct from status, which is about whether it reached the agent.","type":"object","allOf":[{"$ref":"#/components/schemas/MessageDeliveryDto"}]},"content":{"type":"object","description":"Raw event content (stream-json shape)"},"attachments":{"description":"Files attached to this message (operator upload or the agent attachment_send).","type":"array","items":{"$ref":"#/components/schemas/MessageAttachmentDto"}},"created_at":{"format":"date-time","type":"string","description":"Created at"}},"required":["id","conversation_id","seq","role","kind","status","content","created_at"]},"ListMessageDto":{"type":"object","properties":{"data":{"description":"Messages","type":"array","items":{"$ref":"#/components/schemas/GetMessageDto"}},"total":{"type":"number","description":"Total messages in conversation"}},"required":["data","total"]},"ConversationAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"soki"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar proxy URL (null = use generative)"},"provider":{"type":"string","nullable":true,"description":"Provider the agent's container actually booted against, so the picker can offer only models it can run. Resolved by the spawn's own precedence: its pinned connection, else the catalogue provider of the model it runs (its own, or its image default), else the org's single shared connection. Null when there is no way to tell — it used to read \"anthropic\" there, which was a guess dressed as an answer.","example":"anthropic"}},"required":["id","name","avatar_url"]},"ConversationListItemDto":{"type":"object","properties":{"id":{"type":"number","description":"Conversation id","example":1},"ref":{"type":"string","description":"Opaque public reference — paste it to jump to this conversation.","example":"MZROL9UC"},"status":{"type":"string","description":"Status","example":"OPEN"},"model":{"type":"string","nullable":true,"description":"Last Claude model seen (slug). Null until first reply.","example":"claude-haiku-4-5"},"model_override":{"type":"string","nullable":true,"description":"Operator/agent-set model override for this conversation (KJ-22). Null = inherit the agent default. Distinct from `model` (what last ran).","example":"claude-haiku-4-5"},"connection":{"nullable":true,"description":"Connection this conversation runs with when it is not the one of its agent. Null = the connection of the agent.","type":"object","allOf":[{"$ref":"#/components/schemas/ConversationConnectionDto"}]},"effort_override":{"type":"string","nullable":true,"description":"Reasoning effort set for this conversation (#277): LOW/MEDIUM/HIGH/XHIGH/MAX. Null = inherit the agent default.","example":"HIGH"},"effective_model":{"type":"string","nullable":true,"description":"The model this conversation will actually run its NEXT turn with, resolved server-side by the shared precedence chain (conversation → agent → image). Lets a row say what it runs on without waiting for a first reply.","example":"claude-opus-5"},"effective_connection_id":{"type":"number","nullable":true,"description":"The connection that will serve the NEXT turn: the conversation's own, or the one annotated on its agent. Lets a row mark WHICH of several connections of the same provider its default model belongs to. Null when the agent inherits without an annotated connection (nothing is deduced per row).","example":3},"context_tokens":{"type":"number","nullable":true,"description":"Tokens of context this conversation is currently carrying. Null until its first turn.","example":96000},"context_window":{"type":"number","description":"The effective model's context window, so the row can turn `context_tokens` into a percentage without knowing the model catalogue.","example":1000000},"reset_threshold":{"type":"number","nullable":true,"description":"Tokens at which this conversation compacts in place, resolved by the same chain every turn uses (conversation → agent → organization). Null = Kujira does not compact it.","example":150000},"context_cap_tokens":{"type":"number","nullable":true,"description":"This conversation's own context cap: null inherits the agent/organization, 0 = no cap, otherwise the tokens it compacts at.","example":null},"agent":{"nullable":true,"description":"Owning agent (null if unassigned)","type":"object","allOf":[{"$ref":"#/components/schemas/ConversationAgentDto"}]},"contact":{"description":"Contact summary","allOf":[{"$ref":"#/components/schemas/ConversationContactDto"}]},"channel":{"description":"Channel summary","allOf":[{"$ref":"#/components/schemas/ConversationChannelDto"}]},"last_activity_at":{"format":"date-time","type":"string","description":"Last activity"},"debug_visible_until":{"format":"date-time","type":"string","nullable":true,"description":"Debug opt-in expiry (KUJI-41 Fase 4). When in the future, the owner has exposed this personal conversation to admins/service for troubleshooting. Null = private."}},"required":["id","ref","status","model","model_override","connection","effort_override","effective_model","effective_connection_id","context_tokens","context_window","reset_threshold","context_cap_tokens","agent","contact","channel","last_activity_at"]},"ConversationListPageDto":{"type":"object","properties":{"rows":{"description":"Conversations in this page","type":"array","items":{"$ref":"#/components/schemas/ConversationListItemDto"}},"total":{"type":"number","description":"Total matching the filters","example":1234},"limit":{"type":"number","description":"Page size","example":50},"offset":{"type":"number","description":"Offset","example":0}},"required":["rows","total","limit","offset"]},"CredentialInEffectDto":{"type":"object","properties":{"provider":{"type":"string","nullable":true,"description":"The provider its model resolves to: where the credential is looked up. Null when there is no way to know — no saved connection, no model the catalogue recognizes, and no own credential that says so.","example":"anthropic"},"source":{"enum":["OWN","ORG","NONE"],"type":"string","description":"Whose it is: OWN the one pasted into this agent, ORG the organization's connector, NONE none usable — with NONE the agent does not start.","example":"ORG"},"kind":{"type":"string","nullable":true,"description":"How the organization's is paid for (SUBSCRIPTION / API_KEY) or how the agent's own authenticates (OAUTH / API_KEY). Null with source NONE.","example":"SUBSCRIPTION"},"connection_id":{"type":"number","nullable":true,"description":"WHICH connection answers, when one does (source ORG): the pinned one, or the one the agent inherits. Null with OWN and NONE. With several connections per provider, the provider alone no longer names the one the agent is running on.","example":12}},"required":["source"]},"NotAnsweringDto":{"type":"object","properties":{"code":{"type":"string","description":"Code for the cause, stable even if the text gets rewritten.","example":"oauth_org_not_allowed"},"reason":{"type":"string","description":"The cause as a short label, for a pill or a chip.","example":"Claude Code desactivado en la cuenta"},"detail":{"type":"string","description":"The cause explained, with what needs to be done to fix it.","example":"the Anthropic account has Claude Code access disabled, so no turn of this agent gets to start"},"since":{"format":"date-time","type":"string","description":"Since when it has not been answering."}},"required":["code","reason","detail","since"]},"GetAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":1},"organization_id":{"type":"number","description":"Organization id","example":1},"server_id":{"type":"number","description":"Server id this agent runs on","example":1},"image_id":{"type":"number","description":"AgentImage id pinned to this agent","example":1},"name":{"type":"string","description":"Display name","example":"sales-bot-eu"},"description":{"type":"string","nullable":true,"description":"Free-form description"},"role":{"type":"string","nullable":true,"description":"What the agent is FOR. Null while nobody has said: the AI Doctor proposes one from the identity and a person confirms it.","example":"sales"},"status":{"enum":["SPAWNING","RUNNING","IDLE","INPUT","PAUSING","PAUSED","RESUMING","STOPPING","STOPPED","ERROR","DELETING"],"type":"string","description":"Lifecycle status — driven by the supervisor once running","example":"STOPPED"},"viewer_access":{"nullable":true,"enum":["CHAT","MANAGE"],"type":"string","description":"The requesting member's access level on this agent (KUJI-41 F2): 'MANAGE' (admin/service or a MANAGE grant), 'CHAT' (view+converse only), or null. Lets the UI hide admin actions / filter assignment pickers. Undefined for internal/no-session reads.","example":"MANAGE"},"credential_choice":{"enum":["API_KEY","INHERIT","SUBSCRIPTION"],"type":"string","description":"DEPRECATED and no longer read: what the agent runs on is the connection in `model_provider_id`, not a credential type. Kept in the response with its stored value while the column is still there; it decides nothing. See `credential_in_effect`.","example":"INHERIT"},"model_provider_id":{"type":"number","nullable":true,"description":"The organization connection this agent starts with. It used to be inferred from its model name; now it is stored, because an organization can have SEVERAL connections of the same provider (one Ollama per machine) and \"uses Ollama\" does not say which one. Null = still inferred, which is what happens when the organization has no active connection for its provider or when the agent runs with the credential pasted into it directly. When it is null, `credential_in_effect.connection_id` says which one it inherits.","example":12},"credential_in_effect":{"description":"Which credential this agent would start with RIGHT NOW, already resolved. It is the answer to \"where does it get its credentials from?\", and it comes from the control layer precisely so the panel does not have to rebuild it: the rule — its own wins, but only if it is for the provider its model resolves to today — is easy to get wrong, and written twice it drifts out of sync (#616).","allOf":[{"$ref":"#/components/schemas/CredentialInEffectDto"}]},"model_override":{"type":"string","nullable":true,"description":"Claude model slug override. Null → use whatever the image defaults to.","example":"claude-sonnet-4-6"},"resolved_model":{"type":"string","nullable":true,"description":"Effective model the agent would spawn with now (override ?? image default). Null = claude binary default.","example":"claude-opus-4-8"},"context_floor_tokens":{"type":"number","description":"Tokens the agent loads on EVERY step before anyone speaks (memories, skills, base prompt). Lets the list compare the fleet without opening each context map. Approximate — the exact breakdown is the context manifest.","example":67000},"context_floor_memory_tokens":{"type":"number","description":"How much of that floor is short-term memories, the part usually worth moving.","example":46000},"context_floor_recommended_tokens":{"type":"number","description":"What we advise not to exceed at boot, measured against whatever really limits this agent (its session-reset cap, or the model window when uncapped).","example":60000},"context_floor_cap_tokens":{"type":"number","nullable":true,"description":"The session-reset cap this agent compacts at, or null when uncapped.","example":300000},"running_model":{"type":"string","nullable":true,"description":"Model the agent was last actually spawned with. Differs from resolved_model → a restart is pending to apply the change.","example":"claude-opus-4-7"},"running_provider":{"type":"string","nullable":true,"description":"Provider the running container was started against, recorded from the credential it actually used. Differs from credential_in_effect.provider → a restart is pending to switch provider. null = never started, or started before this was recorded.","example":"openrouter"},"analysis_score":{"type":"number","nullable":true,"description":"Latest config-analysis score 0-100 (KUJI-90). null if never analyzed.","example":72},"effort_override":{"nullable":true,"enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"],"type":"string","description":"Reasoning-effort override → CLI --effort (LOW/MEDIUM/HIGH/XHIGH/MAX). The modern unified depth control; supersedes thinking on adaptive models. Null = not set (claude defaults to high).","example":"HIGH"},"thinking_enabled":{"type":"boolean","nullable":true,"description":"Force --thinking on or off for this agent. Null → use the image default.","example":true},"language":{"type":"string","nullable":true,"description":"BCP-47 / ISO language code appended to the system prompt by the image start script.","example":"es"},"mcp_http_bridge":{"type":"boolean","nullable":true,"description":"Wrap remote HTTP/SSE MCP servers in a local stdio bridge to stop per-turn reconnect churn (KUJI-34). Null/false → off.","example":true},"response_style":{"enum":["DEFAULT","EXTENDED","SUMMARIZED","MINIMAL"],"type":"string","description":"Reply DETAIL (KUJI-53/62): DEFAULT (platform default), EXTENDED (full), SUMMARIZED (concise), or MINIMAL (just the essential).","example":"DEFAULT"},"response_format":{"enum":["PROSE","SCANNABLE"],"type":"string","description":"Reply FORMAT (KUJI-62): PROSE (normal sentences) or SCANNABLE (headline + bullets, actionable first).","example":"PROSE"},"single_message":{"type":"boolean","description":"Reply MESSAGES (KUJI-62): false = may narrate steps as separate messages; true = work silently, send ONE message per turn.","example":false},"no_emoji":{"type":"boolean","description":"Reply EMOJI (KUJI-62): false = may use emojis where they aid scanning; true = NEVER use emojis (customer-facing agents).","example":false},"approval_ask_threshold":{"type":"number","description":"Approval \"ask\" threshold (0-100): the agent acts alone below it and asks the operator (approval_request with a self-assessed level) at or above it.","example":70},"approval_block_threshold":{"type":"number","description":"Approval \"block\" threshold (0-100, >= ask): at or above it the agent waits for the human no matter what; in the [ask, block) band it asks but auto-proceeds after approval_timeout_minutes.","example":90},"approval_timeout_minutes":{"type":"number","description":"Minutes the agent waits for a decision in the auto-proceed band before continuing on its own.","example":60},"approval_categories":{"type":"array","items":{"required":true,"description":"Always-ask overrides (on top of the thresholds): free-text actions that ALWAYS require approval regardless of the agent's level estimate. Empty = thresholds only.","example":["Spend money: purchases, payments or subscriptions","Deactivate a customer"],"type":"array","items":{"type":"string"}}},"disabled_tool_groups":{"description":"Tool families this agent may NOT use. Empty = it can use everything.","type":"array","items":{"type":"string"}},"memory_mb_override":{"type":"number","nullable":true,"description":"RAM ceiling for the agent container in MB. Null = inherit the server default (or unlimited if the server sets none). Per-agent override that wins over the server default.","example":2048},"cpu_override":{"type":"number","nullable":true,"description":"CPU ceiling for the agent container in cores. Null = inherit the server default (or unlimited if the server sets none). Per-agent override that wins over the server default.","example":2},"hub_available":{"type":"boolean","description":"Whether this agent is listed as an assignee candidate in the external-conversations Agent Desk. Defaults to false so internal-only agents stay invisible to customers.","example":true},"voice_enabled":{"type":"boolean","description":"Whether the voice channel (TTS replies) is enabled for this agent.","example":false},"network_privileged":{"type":"boolean","description":"Privileged networking (KJ-156): container gets /dev/net/tun + CAP_NET_ADMIN so the agent can run a VPN (Tailscale/WireGuard/…). Applied on the next spawn.","example":false},"voice_id":{"type":"string","nullable":true,"description":"ElevenLabs voice id for this agent's TTS, or null.","example":"dNjJKg63Fr5AXwIdkATa"},"backup_schedule":{"enum":["INHERIT","OFF","CUSTOM"],"type":"string","description":"Scheduled-backup mode: INHERIT (org default), OFF (disabled), or CUSTOM (own schedule).","example":"INHERIT"},"timezone":{"type":"string","nullable":true,"description":"Custom backup cron (UTC) when backup_schedule=CUSTOM. Null otherwise.","example":"0 */6 * * *"},"backup_retention":{"type":"number","nullable":true,"description":"Custom retention (SCHEDULED backups to keep) when CUSTOM. Null otherwise.","example":10},"cost_guard_mode":{"enum":["INHERIT","OFF","CUSTOM"],"type":"string","description":"Cost-guard mode (KUJI-51): INHERIT (org default), OFF (disabled), or CUSTOM (own threshold).","example":"INHERIT"},"cost_guard_tokens_per_hour":{"type":"number","nullable":true,"description":"Custom hourly token threshold when cost_guard_mode=CUSTOM. Null otherwise.","example":500000},"cost_guard_action":{"nullable":true,"enum":["NOTIFY","PAUSE"],"type":"string","description":"Custom guard action (NOTIFY/PAUSE) when CUSTOM. Null = inherit."},"session_reset_mode":{"enum":["INHERIT","OFF","CUSTOM"],"type":"string","description":"Session auto-reset mode (KUJI-51): INHERIT (org default), OFF (never), or CUSTOM (own token cap).","example":"INHERIT"},"session_reset_tokens":{"type":"number","nullable":true,"description":"Own compaction threshold in tokens when CUSTOM (capped to the model window on use). Null otherwise.","example":300000},"context_window":{"type":"number","description":"Context window of the model this agent would spawn with (resolved_model), the connection's declared window first.","example":1000000},"session_reset_effective_tokens":{"type":"number","description":"Tokens at which this agent's sessions compact, resolved from its mode and the org share of its model window (#698). 0 = Kujira doesn't compact (the CLI still auto-compacts at the edge of the window).","example":300000},"session_reset_inherited_tokens":{"type":"number","description":"What session_reset_effective_tokens would be in INHERIT mode, whatever the current mode: lets a client show what inheriting means for this agent before switching to it.","example":300000},"last_backup_at":{"format":"date-time","type":"string","nullable":true,"description":"Timestamp of the agent's most recent COMPLETED backup. Null if never backed up."},"container_id":{"type":"string","nullable":true,"description":"Container id assigned by Docker (null when not running)"},"last_action":{"type":"string","nullable":true,"description":"Last action reported by the agent","example":"Analyzing diff in src/auth/session.ts"},"last_action_at":{"format":"date-time","type":"string","nullable":true,"description":"Timestamp of the last reported action"},"auth_failed_at":{"format":"date-time","type":"string","nullable":true,"description":"When the provider rejected this agent's token, or null if it works. Cleared as soon as the agent completes a turn."},"not_answering":{"nullable":true,"description":"Why this agent is not answering anyone, or null if it is answering. Not the same as status: the container can be RUNNING and healthy while every turn dies on arrival. It clears itself as soon as a turn completes.","type":"object","allOf":[{"$ref":"#/components/schemas/NotAnsweringDto"}]},"uptime_seconds":{"type":"number","nullable":true,"description":"Container uptime in seconds (null when not running)"},"tokens_used":{"type":"string","description":"Total tokens consumed by the agent (string to preserve BigInt precision)","example":"142000"},"cost_micro":{"type":"string","description":"Accumulated cost in 1e-6 currency units (string to preserve BigInt precision). 2.84 in currency = \"2840000\".","example":"2840000"},"usage_status":{"type":"string","nullable":true,"description":"Latest Anthropic rate-limit status for this agent (ALLOWED / ALLOWED_WARNING / EXCEEDED). Null when no snapshot has been received yet.","example":"ALLOWED"},"usage_resets_at":{"format":"date-time","type":"string","nullable":true,"description":"Wall-clock moment Anthropic will reset the current rate-limit window. Null when no snapshot has been received yet."},"usage_rate_limit_type":{"type":"string","nullable":true,"description":"Which rate-limit bucket triggered the event: FIVE_HOUR (rolling 5h window) or WEEKLY (Max-plan weekly cap).","example":"FIVE_HOUR"},"usage_overage_status":{"type":"string","nullable":true,"description":"Anthropic \"overage\" status (pay-as-you-go burst credit). REJECTED with overageDisabledReason \"org_level_disabled\" is the textbook \"the OAuth token belongs to a different Anthropic org than the operator expects\" diagnostic.","example":"ALLOWED"},"usage_overage_resets_at":{"format":"date-time","type":"string","nullable":true,"description":"Wall-clock moment the overage window resets."},"usage_is_overage":{"type":"boolean","nullable":true,"description":"True when the agent is currently consuming the overage allowance.","example":false},"usage_updated_at":{"format":"date-time","type":"string","nullable":true,"description":"Server timestamp when the usage snapshot was last refreshed."},"sync_pending":{"type":"boolean","description":"True when skills/memories changed and the supervisor has not yet picked them up","example":false},"avatar_url":{"type":"string","nullable":true,"description":"Avatar URL — points at the backend proxy that streams from R2. Includes a v=<timestamp> cache-buster so a replacement is picked up on the next render. Null when no avatar has been uploaded.","example":"/org/1/agent/3/avatar?v=1779650000000"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"backup_cron":{"type":"string","nullable":true},"backup_freeze":{"type":"boolean"}},"required":["id","organization_id","server_id","image_id","name","status","credential_choice","credential_in_effect","response_style","response_format","single_message","no_emoji","approval_ask_threshold","approval_block_threshold","approval_timeout_minutes","approval_categories","hub_available","voice_enabled","network_privileged","voice_id","backup_schedule","cost_guard_mode","session_reset_mode","context_window","session_reset_effective_tokens","session_reset_inherited_tokens","tokens_used","cost_micro","sync_pending","created_at","updated_at","backup_cron","backup_freeze"]},"ListAgentDto":{"type":"object","properties":{"data":{"description":"Items in the current page","type":"array","items":{"$ref":"#/components/schemas/GetAgentDto"}},"total":{"type":"number","description":"Total number of items matching the query","example":42},"page":{"type":"number","description":"Current page (1-indexed)","example":1},"limit":{"type":"number","description":"Page size","example":20}},"required":["data","total","page","limit"]},"CreateAgentDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Display name (unique within the org)","example":"sales-bot-eu"},"description":{"type":"string","maxLength":500,"description":"Free-form description","example":"Handles EU leads in the sales pipeline"},"role":{"type":"string","maxLength":80,"description":"What the agent is FOR: «sales», «customer support», «clinic reception». Free text, not a closed list. Left empty, the AI Doctor proposes one from the agent identity and a person confirms it — it is never rewritten on its own.","example":"sales"},"server_id":{"type":"number","minimum":1,"description":"Server where the agent will run. Must belong to the same org. Discover it with `GET /org/{org_id}/server`.","example":1},"image_id":{"type":"number","minimum":1,"description":"AgentImage version pinned to this agent. Must be available. Omit it to use the catalogue default (the image with `is_default: true` in `GET /agent-image`), which is the usual choice.","example":1},"model_provider_id":{"type":"number","minimum":1,"description":"The organization connection this agent boots with. Omit and it is resolved from the model: the default connection of its provider. Pass an id to say which one: with several connections of the same provider, \"runs on Ollama\" does not say which machine. Must belong to this organization and be turned on. Naming one needs `model_provider.view` on top of `agent.create`: choosing from the list means being allowed to see it.","example":12},"model_override":{"type":"string","maxLength":80,"pattern":"^$|^[A-Za-z0-9._[\\]-]+$","description":"Model this agent runs, from the catalogue (any provider). Required unless `model_provider_id` is a connection that brings its own model (Ollama, OpenRouter); without either the agent is rejected with MODEL_REQUIRED. The image does not carry a model — a model of any provider is valid here as long as the org has a connection for it.","example":"claude-sonnet-5"}},"required":["name","server_id"]},"UpdateAgentDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Display name (unique within the org)","example":"sales-bot-eu"},"image_id":{"type":"number","minimum":1,"description":"Switch the agent to a different image from the catalogue (e.g. base → flex). The image must be available. Changing it only updates the row; call POST /:id/update-image to pull the new tag and recreate the container — the volume, session_id and conversations are preserved. The server cannot be changed this way.","example":3},"description":{"type":"string","maxLength":500,"description":"Free-form description"},"role":{"type":"string","maxLength":80,"description":"What the agent is FOR: «sales», «customer support», «clinic reception». Free text, not a closed list. Left empty, the AI Doctor proposes one from the agent identity and a person confirms it — it is never rewritten on its own.","example":"sales"},"timezone":{"type":"string","nullable":true,"description":"IANA time zone the schedules are read in (\"Europe/Madrid\"). Overrides the organization zone for the crons of this agent; empty inherits. Rejected if the runtime does not know the zone.","example":"Europe/Madrid"},"credential_choice":{"enum":["API_KEY","INHERIT","SUBSCRIPTION"],"type":"string","description":"DEPRECATED and ignored since an organization can have several connections per provider: a credential TYPE no longer identifies one. Use `model_provider_id` to say which connection the agent runs on. Still accepted so a client that sends it keeps working, but it changes nothing.","example":"INHERIT"},"model_provider_id":{"type":"number","nullable":true,"minimum":1,"description":"The organization connection this agent boots with. Pass an id to pin one — the only way to choose between several connections of the SAME provider (one Ollama per machine), where \"use Ollama\" doesn't say which. Null goes back to resolving it from the agent's model. Omit and it is recomputed whenever the model changes and the current connection stops serving it. Must belong to this organization and be turned on; choosing among the connections that already exist needs `agent.edit` plus `model_provider.view` (naming one means being allowed to see the list), creating or rotating one still needs `model_provider.edit`.","example":12},"model_override":{"type":"string","maxLength":80,"pattern":"^$|^[A-Za-z0-9._[\\]-]+$","description":"Model slug override (e.g. claude-sonnet-4-6, MiniMax-M3). Must be a slug from the catalogue. Empty string clears the override and returns the agent to the image default.","example":"claude-sonnet-4-6"},"thinking_enabled":{"type":"boolean","nullable":true,"description":"Force --thinking on or off for this agent. Pass null to clear the override and fall back to the image default.","example":true},"effort_override":{"nullable":true,"enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"],"type":"string","description":"Reasoning-effort override → CLI --effort (LOW/MEDIUM/HIGH/XHIGH/MAX). Pass null to clear and fall back to the claude default (high). Supersedes --thinking on adaptive models.","example":"HIGH"},"language":{"type":"string","maxLength":10,"pattern":"^$|^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})?$","description":"BCP-47 / ISO language code. Empty string clears the override.","example":"es"},"approval_ask_threshold":{"type":"number","minimum":0,"maximum":100,"description":"Approval \"ask\" threshold (0-100): the agent acts alone below it, asks at/above it. Takes effect on the next spawn/restart.","example":70},"approval_block_threshold":{"type":"number","minimum":0,"maximum":100,"description":"Approval \"block\" threshold (0-100, kept >= ask server-side): at/above it the agent waits no matter what; between ask and block it auto-proceeds after the timeout.","example":90},"approval_timeout_minutes":{"type":"number","minimum":1,"description":"Minutes to wait for a decision in the auto-proceed band before continuing.","example":60},"approval_categories":{"type":"array","items":{"required":false,"maxItems":50,"description":"Always-ask overrides (on top of the thresholds): free-text actions that ALWAYS require approval. Empty array = thresholds only. Blank items are dropped server-side.","example":["Gastar dinero: compras, pagos o suscripciones","Dar de baja a un cliente"],"type":"array","items":{"type":"string","maxLength":300}}},"disabled_tool_groups":{"type":"array","items":{"type":"string","enum":["credentials","scheduling","mcp_servers","third_party_access","self_management","outbound","teammates","knowledge"]},"description":"Tool families this agent may NOT use (#302). Empty = it can use everything, which is how every agent behaved before this existed. Enforced server-side on every MCP call, not just by not announcing them.","example":["credentials","mcp_servers"]},"mcp_http_bridge":{"type":"boolean","nullable":true,"description":"Wrap remote HTTP/SSE MCP servers in a local stdio bridge to stop per-turn reconnect churn (KUJI-34). Pass null/false to disable. Takes effect on the next spawn/restart.","example":true},"response_style":{"enum":["DEFAULT","EXTENDED","SUMMARIZED","MINIMAL"],"type":"string","description":"Reply DETAIL (KUJI-53/62). DEFAULT follows the platform default; EXTENDED = full; SUMMARIZED = concise; MINIMAL = just the essential.","example":"DEFAULT"},"response_format":{"enum":["PROSE","SCANNABLE"],"type":"string","description":"Reply FORMAT (KUJI-62). PROSE = normal sentences; SCANNABLE = headline + bullets, actionable first.","example":"PROSE"},"single_message":{"type":"boolean","description":"Reply MESSAGES (KUJI-62). false = may narrate steps; true = work silently, send ONE message per turn.","example":false},"no_emoji":{"type":"boolean","description":"Reply EMOJI (KUJI-62). false = may use emojis where they help; true = NEVER use emojis (customer-facing).","example":false},"memory_mb_override":{"type":"number","nullable":true,"minimum":64,"maximum":131072,"description":"RAM ceiling override for this agent in MB. Null clears the override (falls back to the server default, or unlimited if the server sets none).","example":2048},"cpu_override":{"type":"number","nullable":true,"minimum":0.1,"maximum":128,"description":"CPU ceiling override for this agent in cores. Null clears the override (falls back to the server default, or unlimited if the server sets none).","example":2},"hub_available":{"type":"boolean","description":"Whether this agent appears in the Agent Desk assignee picker. False (default) hides it from external-conversations workflows.","example":true},"voice_enabled":{"type":"boolean","description":"Enable the voice channel (TTS replies) for this agent (KUJI — voice).","example":true},"network_privileged":{"type":"boolean","description":"Privileged networking (KJ-156): spawn the container with /dev/net/tun + CAP_NET_ADMIN so the agent can run a VPN. Powerful — opt-in. Applies on the next spawn (needs a recreate).","example":false},"voice_id":{"type":"string","description":"ElevenLabs voice id for this agent's TTS. Empty string clears it.","example":"dNjJKg63Fr5AXwIdkATa"},"backup_schedule":{"enum":["INHERIT","OFF","CUSTOM"],"type":"string","description":"Scheduled-backup mode (KUJI-43). INHERIT (default) uses the org schedule; OFF disables backups for this agent; CUSTOM uses backup_cron/backup_retention below.","example":"INHERIT"},"backup_cron":{"type":"string","nullable":true,"description":"Custom backup schedule (cron, UTC) when backup_schedule=CUSTOM. Empty/null clears it.","example":"0 */6 * * *"},"backup_retention":{"type":"number","nullable":true,"minimum":1,"maximum":365,"description":"How many SCHEDULED backups to keep for this agent (when CUSTOM).","example":10},"backup_freeze":{"type":"boolean","description":"Freeze this agent while its disk is read, so the copy cannot catch a file half-written. It is unreachable for the duration of the tar (minutes on a big volume) and its open connections may time out, so it is off by default and the call is the operator's.","example":false},"cost_guard_mode":{"enum":["INHERIT","OFF","CUSTOM"],"type":"string","description":"Cost-guard mode (KUJI-51). INHERIT (default) uses the org guard; CUSTOM uses the threshold/action below; OFF drops both. On a standard plan OFF does NOT leave the agent unguarded: it falls back to the plan's hourly ceiling, which cannot be switched off from here. Only ENTERPRISE, which negotiates its own, can run with no guard at all.","example":"INHERIT"},"cost_guard_tokens_per_hour":{"type":"number","nullable":true,"minimum":0,"description":"Custom hourly token threshold when cost_guard_mode=CUSTOM. Null/0 clears your number; on a standard plan the plan's ceiling then applies. A value BELOW the plan's is honoured — tightening the guard is always allowed, switching it off is not.","example":500000},"cost_guard_action":{"nullable":true,"enum":["NOTIFY","PAUSE"],"type":"string","description":"Custom guard action (NOTIFY/PAUSE) when CUSTOM."},"session_reset_mode":{"enum":["INHERIT","OFF","CUSTOM"],"type":"string","description":"Conversation compaction mode (KUJI-51). INHERIT (default) uses the org share of the model window; OFF never compacts; CUSTOM uses session_reset_tokens below.","example":"INHERIT"},"session_reset_tokens":{"type":"number","nullable":true,"minimum":20000,"maximum":900000,"description":"Own compaction threshold in tokens when CUSTOM (20k–900k). Capped to the model's window on use.","example":300000}},"required":["approval_categories"]},"AgentImageCapabilityDto":{"type":"object","properties":{"id":{"type":"number","description":"Capability id","example":1},"key":{"type":"string","description":"Stable slug — the agent-base/supervisor look at this.","example":"playwright"},"label":{"type":"string","description":"Display name","example":"Playwright + Chromium"},"description":{"type":"string","nullable":true,"description":"Long description"},"icon":{"type":"string","nullable":true,"description":"Lucide icon name hint for the frontend","example":"theater"}},"required":["id","key","label"]},"GetAgentImageDto":{"type":"object","properties":{"id":{"type":"number","description":"AgentImage id","example":1},"role_key":{"type":"string","description":"Role key (stable identifier across versions)","example":"sales"},"version":{"type":"string","description":"Image version","example":"0.1.0"},"image_tag":{"type":"string","description":"Fully qualified image tag in the registry","example":"ghcr.io/calltek/kj-agent-sales:0.1.0"},"name":{"type":"string","description":"Display name","example":"Sales Agent"},"description":{"type":"string","nullable":true,"description":"Free-form description"},"icon":{"type":"string","nullable":true,"description":"Icon hint for the UI"},"color":{"type":"string","nullable":true,"description":"Color hint for the UI (hex)"},"default_memory_mb":{"type":"number","description":"Default container memory limit in MB","example":512},"default_cpu":{"type":"number","description":"Default container CPU share","example":0.5},"is_available":{"type":"boolean","description":"False to hide from selectors without removing the row"},"is_default":{"type":"boolean","description":"The image a new agent gets when the create omits `image_id`. At most one image is the default, and it is always available."},"capabilities":{"description":"Capabilities pre-installed in the image (internet, playwright, git, …). Read-only from the panel; managed by the Kujira team.","type":"array","items":{"$ref":"#/components/schemas/AgentImageCapabilityDto"}},"avatar_url":{"type":"string","nullable":true,"description":"Avatar URL (cache-busted) or null; the UI falls back to the icon.","example":"/agent-image/8/avatar?v=1717000000000"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"}},"required":["id","role_key","version","image_tag","name","default_memory_mb","default_cpu","is_available","is_default","capabilities","created_at","updated_at"]},"ListAgentImageDto":{"type":"object","properties":{"data":{"description":"Items in the current page","type":"array","items":{"$ref":"#/components/schemas/GetAgentImageDto"}},"total":{"type":"number","description":"Total number of items matching the query","example":3},"page":{"type":"number","description":"Current page (1-indexed)","example":1},"limit":{"type":"number","description":"Page size","example":20}},"required":["data","total","page","limit"]},"GetOrganizationDto":{"type":"object","properties":{"id":{"type":"number","description":"Organization id","example":1},"name":{"type":"string","description":"Organization name","example":"Acme Labs"},"plan":{"enum":["FREE","BASIC","PRO","ENTERPRISE"],"type":"string","description":"Subscription plan","example":"FREE"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar URL — points at the backend proxy that streams from R2. Includes a v=<timestamp> cache-buster so a replacement is picked up on the next render. Null when no avatar has been uploaded.","example":"/org/1/avatar?v=1779650000000"},"viewer_role":{"nullable":true,"enum":["OWNER","ADMIN","OPERATOR","VIEWER","SERVICE"],"type":"string","description":"The requesting user's role in this organization. Lets the frontend gate edit/delete UI. Null when the role can't be resolved.","example":"OWNER"},"viewer_permissions":{"description":"The viewer's effective permission patterns — what the backend will actually evaluate for them. Includes wildcards (`*`) and negations. Empty when the viewer is not a member. Use this to gate the UI; re-deriving it from the role is wrong as soon as a member's permissions are customised.","example":["agent.view","agent.edit"],"type":"array","items":{"type":"string"}},"has_elevenlabs_key":{"type":"boolean","description":"Whether an ElevenLabs API key is configured for the voice channel (KUJI — voice). The key itself is never returned.","example":false},"has_groq_key":{"type":"boolean","description":"Whether a Groq API key is configured for speech-to-text. The key itself is never returned. When false, inbound voice messages are NOT transcribed — there is no platform-wide key behind this one.","example":false},"has_google_oauth_app":{"type":"boolean","description":"Whether the organization uses its own Google app for connectors (#310). Without it, Google accounts cannot be connected. The secret is never returned.","example":false},"google_oauth_client_id":{"type":"string","nullable":true,"description":"The client_id of its Google app, so it can be shown and checked that it is the right one. Not secret: it travels in every authorization URL.","example":"1234-abc.apps.googleusercontent.com"},"timezone":{"type":"string","description":"Org-wide default backup schedule (cron, UTC). Null = no default; agents inherit it unless they override.","nullable":true,"example":"0 3 * * *"},"trial_ends_at":{"format":"date-time","type":"string","nullable":true,"description":"When the PRO trial ends (#395). Null = not on trial: never was, or it already ended."},"grace_until":{"format":"date-time","type":"string","nullable":true,"description":"Until when whatever no longer fits the plan is tolerated, after any downgrade (expired trial, non-payment, or a staff change). Past that date what is over the limit gets STOPPED — nothing is ever deleted. Null = no pending downgrade. This is the countdown the panel shows."},"grace_from_plan":{"nullable":true,"enum":["FREE","BASIC","PRO","ENTERPRISE"],"type":"string","description":"Which plan that downgrade came from, so it can be reported (\"from PRO to FREE\")."},"limits":{"type":"object","properties":{"max_agents":{"type":"number","nullable":true},"max_servers":{"type":"number","nullable":true},"channels_per_agent":{"type":"number","nullable":true},"min_cron_interval_minutes":{"type":"number","nullable":true},"min_mail_poll_minutes":{"type":"number","nullable":true},"doctor_runs_per_month":{"type":"number","nullable":true},"cron_llm_runs_per_month":{"type":"number","nullable":true},"file_versions":{"type":"number","nullable":true}},"required":["max_agents","max_servers","channels_per_agent","min_cron_interval_minutes","min_mail_poll_minutes","doctor_runs_per_month","cron_llm_runs_per_month","file_versions"]},"support_access_until":{"format":"date-time","type":"string","nullable":true,"description":"Until when platform support can access this organization. Null or past = cannot. Granted by the owner and expires on its own."},"support_access_granted_by":{"type":"number","nullable":true,"description":"Who granted that access and when, so the customer can review it."},"support_access_granted_at":{"format":"date-time","type":"string","nullable":true},"customer_type":{"nullable":true,"enum":["BUSINESS","INDIVIDUAL"],"type":"string","description":"Business or individual (#417). Decides which data is required: a business must provide all of it, an individual under €400 only the country, because their simplified invoice does not carry the rest. `null` = not declared.","example":"BUSINESS"},"tax_name":{"type":"string","nullable":true,"description":"Name or legal entity name shown on the invoice (#417).","example":"Acme Labs SL"},"tax_id":{"type":"string","nullable":true,"description":"Tax ID (NIF/CIF/VAT). Optional: an individual may not have one.","example":"B12345678"},"tax_country":{"type":"string","nullable":true,"description":"Country in ISO 3166-1 alpha-2. This is what decides the invoice VAT, even without a tax ID: a consumer is charged the rate of THEIR country.","example":"ES"},"tax_address":{"type":"string","nullable":true,"description":"Billing address."},"tax_postal_code":{"type":"string","nullable":true,"description":"Billing postal code."},"tax_city":{"type":"string","nullable":true,"description":"Billing city."},"vat_validated":{"type":"boolean","nullable":true,"description":"Whether the tax ID was checked against VIES and came back valid. This is the proof that justifies a 0% intra-community rate."},"vat_validated_at":{"format":"date-time","type":"string","nullable":true,"description":"When that check was performed."},"backup_retention":{"type":"number","nullable":true,"description":"How many SCHEDULED backups to keep per agent (org default).","example":7},"cost_guard_tokens_per_hour":{"type":"number","nullable":true,"description":"Org-wide cost guardrail: max spend per agent per hour (1e-6 units). Null/0 = off.","example":500000},"cost_guard_action":{"enum":["NOTIFY","PAUSE"],"type":"string","description":"What the cost guard does on breach: NOTIFY or PAUSE.","example":"NOTIFY"},"session_reset_percent":{"type":"number","description":"Org-wide default: compact a live conversation once its context passes this percentage of its model's context window (#698). 100 = Kujira doesn't compact (Claude Code does at the edge). Agents inherit unless they override.","example":100},"session_reset_tokens":{"type":"number","nullable":true,"description":"Optional org token cap (#698): compact at this many tokens even if the percentage comes later. Null = no cap.","example":300000},"transcript_retention_days":{"type":"number","nullable":true,"description":"Transcript retention override in days (KUJI-113). null = the retention is derived from the plan default. Only ENTERPRISE orgs can set it.","example":365},"contracted_agents":{"type":"number","nullable":true,"description":"Agents the org pays for (#394, per-agent pricing). Governs how many agents and servers it may create. null = not contracted yet: paid plans fall back to the hard cap (50), FREE is always 1. Staff-set until billing exists.","example":3},"max_channels_per_agent":{"type":"number","nullable":true,"description":"Per-org override of the external-channel allowance per contracted agent (#394). null = plan default (BASIC 3, PRO/ENTERPRISE 5). Staff-set.","example":10},"max_hosts":{"type":"number","nullable":true,"description":"Per-org override of the device (kj-host) allowance. null = plan default (FREE 1, BASIC 5, PRO 10, ENTERPRISE bespoke). Staff-set.","example":10},"doctor_runs_per_month":{"type":"number","nullable":true,"description":"Per-org override of AI Doctor passes per month (#394). null = plan default. Staff-set, and enforced: a pass beyond the allowance is refused before the model is called.","example":8},"cron_llm_runs_per_month":{"type":"number","nullable":true,"description":"Per-org override of monthly cron runs that wake the agent (#394). null = plan default. Staff-set. Not enforced yet.","example":20000},"file_versions":{"type":"number","nullable":true,"description":"Per-org override of how many versions are kept per memory and per skill (#405). null = plan default. Staff-set; only ENTERPRISE reads it.","example":50},"version_retention":{"enum":["SPREAD","RECENT"],"type":"string","description":"Which versions of a memory or skill survive once its history is full (#405). SPREAD keeps them spaced across time — reaches months back with less grain in the last days; RECENT keeps only the newest. Chosen by the organization in Settings.","example":"SPREAD"},"server_alert_ram_pct":{"type":"number","nullable":true,"description":"Org default RAM alert threshold (%) for servers (KUJI-136). null = built-in default (85).","example":85},"server_alert_cpu_pct":{"type":"number","nullable":true,"description":"Org default CPU alert threshold (%) for servers. null = built-in default (90).","example":90},"server_alert_load_factor":{"type":"number","nullable":true,"description":"Org default load alert factor (load > factor × cores). null = built-in default (1.5).","example":1.5},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"backup_cron":{"type":"string","nullable":true}},"required":["id","name","plan","viewer_permissions","has_elevenlabs_key","has_groq_key","has_google_oauth_app","limits","cost_guard_action","session_reset_percent","session_reset_tokens","transcript_retention_days","contracted_agents","max_channels_per_agent","max_hosts","doctor_runs_per_month","cron_llm_runs_per_month","file_versions","version_retention","server_alert_ram_pct","server_alert_cpu_pct","server_alert_load_factor","created_at","updated_at","backup_cron"]},"ListOrganizationDto":{"type":"object","properties":{"data":{"description":"Items in the current page","type":"array","items":{"$ref":"#/components/schemas/GetOrganizationDto"}},"total":{"type":"number","description":"Total number of items matching the query","example":42},"page":{"type":"number","description":"Current page (1-indexed)","example":1},"limit":{"type":"number","description":"Page size","example":20}},"required":["data","total","page","limit"]},"GetMemoryDto":{"type":"object","properties":{"id":{"type":"number","description":"Memory id","example":1},"name":{"type":"string","description":"Filename in /home/agent/.claude/memories/","example":"guia-marca.md"},"description":{"type":"string","nullable":true,"description":"One-line summary of what the memory is and when to use it (the skills \"name + description\" pattern). Shown in the UI without opening the file and given to the agent on recall. Null when unset (legacy/free memories).","example":"Brand voice and tone guidelines for customer replies."},"scope":{"enum":["SHORT_TERM","LONG_TERM"],"type":"string","description":"SHORT_TERM = injected at spawn time (working memory). LONG_TERM = referenced on demand via MCP tool (not yet runtime).","example":"SHORT_TERM"},"content_hash":{"type":"string","description":"SHA-256 of `content`, lets the supervisor skip a no-op rewrite"},"assignment_count":{"type":"number","description":"Number of agents this memory is assigned to. Zero = unassigned (orphan).","example":3},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When the memory was archived (soft-deleted). Null on live memories. Archived memories are excluded from default listings and never written to a container volume."},"canonical_kind":{"nullable":true,"enum":["IDENTITY","SOUL"],"type":"string","description":"Set when this is a canonical per-agent memory (auto-seeded on agent creation). IDENTITY = identity.md, SOUL = soul.md. Free memories return null. Canonical memories cannot be archived, deleted, or unassigned from their owning agent.","example":"IDENTITY"}},"required":["id","name","scope","content_hash","assignment_count","created_at","updated_at"]},"ListMemoryDto":{"type":"object","properties":{"rows":{"description":"Page rows","type":"array","items":{"$ref":"#/components/schemas/GetMemoryDto"}},"total":{"type":"number","description":"Total matching rows across all pages","example":31},"limit":{"type":"number","description":"Echo of the requested page size","example":200},"offset":{"type":"number","description":"Echo of the requested offset","example":0}},"required":["rows","total","limit","offset"]},"MemoryAssignedAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"},"assigned_at":{"format":"date-time","type":"string","description":"When the memory was assigned to this agent"}},"required":["id","name","assigned_at"]},"GetMemoryWithContentDto":{"type":"object","properties":{"id":{"type":"number","description":"Memory id","example":1},"name":{"type":"string","description":"Filename in /home/agent/.claude/memories/","example":"guia-marca.md"},"description":{"type":"string","nullable":true,"description":"One-line summary of what the memory is and when to use it (the skills \"name + description\" pattern). Shown in the UI without opening the file and given to the agent on recall. Null when unset (legacy/free memories).","example":"Brand voice and tone guidelines for customer replies."},"scope":{"enum":["SHORT_TERM","LONG_TERM"],"type":"string","description":"SHORT_TERM = injected at spawn time (working memory). LONG_TERM = referenced on demand via MCP tool (not yet runtime).","example":"SHORT_TERM"},"content_hash":{"type":"string","description":"SHA-256 of `content`, lets the supervisor skip a no-op rewrite"},"assignment_count":{"type":"number","description":"Number of agents this memory is assigned to. Zero = unassigned (orphan).","example":3},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When the memory was archived (soft-deleted). Null on live memories. Archived memories are excluded from default listings and never written to a container volume."},"canonical_kind":{"nullable":true,"enum":["IDENTITY","SOUL"],"type":"string","description":"Set when this is a canonical per-agent memory (auto-seeded on agent creation). IDENTITY = identity.md, SOUL = soul.md. Free memories return null. Canonical memories cannot be archived, deleted, or unassigned from their owning agent.","example":"IDENTITY"},"content":{"type":"string","description":"Markdown content of the memory"},"assignments":{"description":"Agents this memory is currently assigned to","type":"array","items":{"$ref":"#/components/schemas/MemoryAssignedAgentDto"}}},"required":["id","name","scope","content_hash","assignment_count","created_at","updated_at","content","assignments"]},"CreateMemoryDto":{"type":"object","properties":{"name":{"type":"string","minLength":4,"maxLength":512,"description":"S3-style key written to /home/agent/.claude/memories/<name>. May contain `/` to nest under folders. Must end in `.md`. The parent folder is created automatically if missing.","example":"comercial/oferta-q2.md"},"content":{"type":"string","minLength":0,"maxLength":200000,"description":"Markdown content","example":"# Guía de marca\n\n- Tono cordial…"},"description":{"type":"string","minLength":0,"maxLength":1024,"description":"One-line summary of what the memory is and when to use it (skills \"name + description\" pattern). Shown in the UI and given to the agent on recall. Optional — keep the body clean markdown, the summary lives here.","example":"Brand voice and tone guidelines for customer replies."},"scope":{"enum":["SHORT_TERM","LONG_TERM"],"type":"string","description":"SHORT_TERM = injected at /home/agent/.claude/memories/ on spawn. LONG_TERM = MCP-fetched on demand (runtime TBD).","example":"SHORT_TERM"},"force":{"type":"boolean","description":"Override the credential-in-content check (#309). When the detector flags a likely API key / PEM / connection string, the save is rejected with a 400 — pass `force: true` only if you know the match is an example, not a real secret. The detector still audits the attempt either way.","example":false}},"required":["name","content","scope"]},"UpdateMemoryDto":{"type":"object","properties":{"name":{"type":"string","minLength":4,"maxLength":512,"description":"Filename (full path including folders)","example":"ventas/oferta-q2.md"},"content":{"type":"string","minLength":0,"maxLength":200000,"description":"Markdown content"},"description":{"type":"string","minLength":0,"maxLength":1024,"description":"One-line summary (skills \"name + description\" pattern). Pass an empty string to clear it.","example":"Brand voice and tone guidelines for customer replies."},"scope":{"enum":["SHORT_TERM","LONG_TERM"],"type":"string"},"force":{"type":"boolean","description":"Override the credential-in-content check (#309). When the detector flags a likely API key / PEM / connection string, the save is rejected with a 400 — pass `force: true` only if you know the match is an example, not a real secret. The detector still audits the attempt either way.","example":false}}},"SetMemoryAgentsDto":{"type":"object","properties":{"agent_ids":{"uniqueItems":true,"description":"Full list of agents this memory should be assigned to. The service syncs: new ids are added, missing ids are removed. Pass [] to detach the memory from every agent.","example":[3,5],"type":"array","items":{"type":"number","minimum":1}}},"required":["agent_ids"]},"GetWebhookConfigDto":{"type":"object","properties":{"outbound_url":{"type":"string","nullable":true,"description":"Outbound POST URL"},"has_outbound_secret":{"type":"boolean","description":"Whether an outbound HMAC secret is set","example":false},"has_inbound_secret":{"type":"boolean","description":"Whether an inbound HMAC secret is set","example":true},"signature_header":{"type":"string","nullable":true,"description":"Header the inbound signature (plain HMAC-SHA256 hex) travels in. Null = default (x-kujira-signature). Plane: x-plane-signature.","example":"x-plane-signature"},"echo_filter":{"type":"object","properties":{"actor_paths":{"type":"array","items":{"type":"string"}},"self_ids":{"type":"array","items":{"type":"string"}}},"required":["actor_paths","self_ids"]}},"required":["has_outbound_secret","has_inbound_secret","echo_filter"]},"GetGithubOAuthDto":{"type":"object","properties":{"authorized":{"type":"boolean","description":"Whether the channel is authorized to act on GitHub","example":true},"user_login":{"type":"string","nullable":true,"description":"The GitHub account the channel posts as (login). Null when not authorized.","example":"n0v4-SYS"},"expires_at":{"type":"string","nullable":true,"description":"When the current access token expires (ISO). Null = non-expiring / unauthorized."}},"required":["authorized"]},"GetGithubConfigDto":{"type":"object","properties":{"installation_id":{"type":"number","nullable":true,"description":"The GitHub App installation id this channel rides.","example":82345678},"repos":{"description":"Repo full_names listened to. ['*'] = all repos.","example":["calltek/kj-backend"],"type":"array","items":{"type":"string"}},"events":{"description":"Event types listened to. ['*'] = all subscribed events.","example":["pull_request","pull_request_review"],"type":"array","items":{"type":"string"}},"listen_scope":{"type":"string","description":"Listening scope: \"all\" = every event of the configured repos/events wakes the agent; \"involved\" = only events that concern it (review requested / assigned / @-mentioned / its own PRs), GitHub-notifications style.","enum":["all","involved"],"example":"all"},"raw_payload":{"type":"boolean","description":"Whether each event carries the full raw webhook payload. False by default — it is ~3.000 tokens per event that the agent re-reads on every step, for ~61 that mean something (#272).","example":false},"oauth":{"description":"Per-channel OAuth identity: whether the channel is authorized to post on GitHub AS a bot account, and as whom (Fase 3).","allOf":[{"$ref":"#/components/schemas/GetGithubOAuthDto"}]}},"required":["repos","events","listen_scope","raw_payload","oauth"]},"GetGoogleConnectionDto":{"type":"object","properties":{"connected":{"type":"boolean","description":"Whether the agent has a Google account connected","example":true},"google_email":{"type":"string","nullable":true,"description":"The connected Gmail address. Null when not connected.","example":"soporte@gmail.com"}},"required":["connected"]},"GetDriveConfigDto":{"type":"object","properties":{"folder_id":{"type":"string","description":"Google Drive folder id being watched","example":"1AbCdEfGhIjKlMnOpQrStUvWxYz"},"folder_name":{"type":"string","description":"Folder display name","example":"Facturas"}},"required":["folder_id","folder_name"]},"GetCalendarEntryDto":{"type":"object","properties":{"id":{"type":"string","description":"Google Calendar id","example":"primary"},"name":{"type":"string","description":"Calendar display name","example":"Agenda Calltek"}},"required":["id","name"]},"GetCalendarConfigDto":{"type":"object","properties":{"calendar_whitelist":{"description":"Calendar allowlist. EMPTY = every calendar of the connected account is processed; entries restrict to those calendars.","type":"array","items":{"$ref":"#/components/schemas/GetCalendarEntryDto"}},"reminder_lead_minutes":{"type":"number","nullable":true,"description":"Reminder lead in minutes (a heads-up before each event starts). Null = changes only.","example":15}},"required":["calendar_whitelist"]},"GetWhatsappConfigDto":{"type":"object","properties":{"linked":{"type":"boolean","description":"Whether an account is linked (someone scanned the code).","example":true},"phone_number":{"type":"string","nullable":true,"description":"The linked account's phone number.","example":"34600111222"},"display_name":{"type":"string","nullable":true,"description":"The name the account displays on WhatsApp.","example":"Sergio"},"linked_at":{"type":"string","nullable":true,"description":"When it was linked.","example":"2026-08-31T10:00:00.000Z"}},"required":["linked","phone_number","display_name","linked_at"]},"GetNotifyConversationDto":{"type":"object","properties":{"id":{"type":"number","description":"Conversation id","example":42},"ref":{"type":"string","description":"Public conversation ref","example":"MZROL9UC"},"title":{"type":"string","nullable":true,"description":"Session title (operator sessions). Null = unnamed/default.","example":"Avisos infra"},"contact_name":{"type":"string","description":"Contact on the other side","example":"Jonatan"},"transport":{"enum":["INTERNAL","WHATSAPP","GMAIL","DISCORD","TELEGRAM","SLACK","WEBHOOK","EMAIL","GITHUB","DRIVE","CALENDAR","HOST"],"type":"string","description":"Transport of the conversation channel","example":"TELEGRAM"}},"required":["id","ref","contact_name","transport"]},"GetChannelDto":{"type":"object","properties":{"id":{"type":"number","description":"Channel id","example":1},"agent_id":{"type":"number","description":"Owning agent id","example":3},"transport":{"enum":["INTERNAL","WHATSAPP","GMAIL","DISCORD","TELEGRAM","SLACK","WEBHOOK","EMAIL","GITHUB","DRIVE","CALENDAR","HOST"],"type":"string","description":"Transport","example":"TELEGRAM"},"scope":{"enum":["EXTERNAL","INTERNAL"],"type":"string","description":"Scope: EXTERNAL (Agent Desk-facing) or INTERNAL (operators/rooms)","example":"EXTERNAL"},"direction":{"enum":["INBOUND","OUTBOUND","BIDIRECTIONAL"],"type":"string","description":"Traffic direction: INBOUND (receive only), OUTBOUND (send only), BIDIRECTIONAL (both).","example":"BIDIRECTIONAL"},"name":{"type":"string","description":"Display name","example":"Soporte Telegram"},"target":{"type":"string","description":"Transport-side target (bot @username for Telegram)","example":"@kujira_support_bot"},"host_id":{"type":"number","nullable":true,"description":"HOST transport: the kj-host device this channel links to. Null otherwise.","example":12},"bot_username":{"type":"string","nullable":true,"description":"Bot username (Telegram)"},"has_token":{"type":"boolean","description":"Whether a bot token is configured (the token itself is never returned)","example":true},"has_signing_secret":{"type":"boolean","description":"SLACK: whether the signing secret is configured (the secret is never returned). Distinguishes \"not yet configured\" from \"one is already set, leave it blank to keep it\".","example":true},"whitelist":{"description":"Inbound whitelist: origin chat/channel ids this channel accepts messages from (Telegram chat id / Discord channel id). Empty means the channel accepts nothing — ids are added explicitly.","example":["1512401528445730899"],"type":"array","items":{"type":"string"}},"label_whitelist":{"description":"GMAIL only: label allowlist. Empty = every inbound email is processed; non-empty = only mail carrying at least one of these Gmail labels gets through (the rest is marked read and skipped). Always empty for other transports.","example":["Kujira"],"type":"array","items":{"type":"string"}},"mention_off":{"description":"Per-chat-id mention exceptions. Every group chat_id requires an @bot mention by DEFAULT before forwarding; chat_ids in this list opt OUT of that — the agent answers every message in those groups. DMs are never gated. Empty list means \"default everywhere\": all groups require a mention.","example":["-100500"],"type":"array","items":{"type":"string"}},"webhook_registered":{"type":"boolean","description":"Whether the inbound webhook has been registered with the provider","example":true},"inbound_path":{"type":"string","nullable":true,"description":"For WEBHOOK channels: the relative inbound path external systems POST to (the secret IS the URL — not a provider auth token). Null for token-based transports, whose webhook_secret stays private.","example":"/webhooks/webhook/ab12cd34"},"invite_url":{"type":"string","nullable":true,"description":"For DISCORD channels: the bot invite URL (built from the public Application ID) with minimal messaging permissions. Null for other transports or when the client_id is unknown.","example":"https://discord.com/oauth2/authorize?client_id=123&scope=bot&permissions=68608"},"webhook":{"nullable":true,"description":"For WEBHOOK channels: editable config (outbound URL, whether secrets are set, signature header + prefix). Secrets are never returned. Null for non-WEBHOOK transports.","type":"object","allOf":[{"$ref":"#/components/schemas/GetWebhookConfigDto"}]},"github":{"nullable":true,"description":"For GITHUB channels: the installation + repo/event filters. Null for other transports.","type":"object","allOf":[{"$ref":"#/components/schemas/GetGithubConfigDto"}]},"google":{"nullable":true,"description":"For GMAIL/DRIVE/CALENDAR channels: the agent's Google connection status. Null for other transports.","type":"object","allOf":[{"$ref":"#/components/schemas/GetGoogleConnectionDto"}]},"drive":{"nullable":true,"description":"For DRIVE channels: the watched folder. Null for other transports.","type":"object","allOf":[{"$ref":"#/components/schemas/GetDriveConfigDto"}]},"calendar":{"nullable":true,"description":"For CALENDAR channels: the watched calendar. Null for other transports.","type":"object","allOf":[{"$ref":"#/components/schemas/GetCalendarConfigDto"}]},"whatsapp":{"nullable":true,"description":"For WHATSAPP channels: which account is linked. Null for other transports.","type":"object","allOf":[{"$ref":"#/components/schemas/GetWhatsappConfigDto"}]},"instructions":{"type":"string","nullable":true,"description":"Operating instructions for an EVENT channel (WEBHOOK/GITHUB/DRIVE/CALENDAR) or a mail channel (EMAIL/GMAIL): what the agent does with the events/emails from this channel, injected as a <system-reminder> per message. Null when unset or for chat transports.","example":"Review PRs where you are requested; approve if clean, else comment."},"notify_conversation_id":{"type":"number","nullable":true,"description":"Escalation destination (#567): the INTERNAL conversation of this same agent where notices/approval prompts born on this channel land (channel_send without an explicit target resolves here). Null = not configured.","example":42},"notify_conversation":{"nullable":true,"description":"Summary of the escalation destination, to name it in the panel. Null when unset.","type":"object","allOf":[{"$ref":"#/components/schemas/GetNotifyConversationDto"}]},"is_active":{"type":"boolean","description":"Active flag","example":true},"inactive_reason":{"type":"string","nullable":true,"description":"Why the channel was deactivated — set by the DRIVE/CALENDAR poller when it cannot get a usable token for the linked connector (missing link or needs reconnecting). Always null while is_active."},"created_at":{"format":"date-time","type":"string","description":"Created at"},"last_activity_at":{"format":"date-time","type":"string","nullable":true,"description":"Last activity at"},"alert_recipient_user_ids":{"description":"Who receives the alerts raised in this channel THREADS THAT BELONG TO NOBODY — a group room, a scheduled task, an unassigned Agent Desk contact. Threads that do belong to someone (an employee chatting with the agent) notify that person instead and never read this. EMPTY MEANS NOBODY, not everybody: what was never configured does not interrupt anyone.","example":[4,9],"type":"array","items":{"type":"number"}}},"required":["id","agent_id","transport","scope","direction","name","target","has_token","has_signing_secret","whitelist","label_whitelist","mention_off","webhook_registered","is_active","created_at","alert_recipient_user_ids"]},"EchoFilterDto":{"type":"object","properties":{"actor_paths":{"description":"Dot-paths into the payload where the event's actor lives (provider-specific, arrays are traversed). E.g. [\"sender.login\"] for GitHub, [\"history_items.user.id\"] for ClickUp.","type":"array","items":{"type":"string","maxLength":256}},"self_ids":{"description":"The agent's OWN identities in that system. An inbound event whose actor matches one of these is dropped. E.g. [\"n0v4-SYS\"].","type":"array","items":{"type":"string","maxLength":256}}}},"WebhookConfigDto":{"type":"object","properties":{"outbound_url":{"type":"string","maxLength":2048,"format":"uri","description":"URL the agent POSTs to (outbound)."},"outbound_secret":{"type":"string","nullable":true,"maxLength":255,"description":"Shared secret to HMAC-sign outbound posts. On PATCH: a string sets it, null removes it, omitting/\"\" keeps the current one."},"inbound_secret":{"type":"string","nullable":true,"maxLength":255,"description":"HMAC secret for INBOUND verification. When set, every incoming POST must carry a valid HMAC-SHA256 of the raw body in the configured header. On PATCH: a string sets it, null removes it (disabling verification), omitting/\"\" keeps the current one. Stored encrypted."},"signature_header":{"type":"string","maxLength":128,"description":"Header carrying the inbound signature (plain HMAC-SHA256 hex). Defaults to x-kujira-signature. Plane uses x-plane-signature, GitHub x-hub-signature-256."},"echo_filter":{"description":"Anti-echo: where the actor lives in the payload + the agent's own ids. Events whose actor is the agent are dropped. On PATCH the whole block is replaced; an empty block clears the filter.","allOf":[{"$ref":"#/components/schemas/EchoFilterDto"}]}}},"ImapConfigDto":{"type":"object","properties":{"host":{"type":"string","maxLength":255},"port":{"type":"number","minimum":1,"maximum":65535},"user":{"type":"string","maxLength":255},"pass":{"type":"string","maxLength":1024},"tls":{"type":"boolean"}},"required":["host","port","user","pass"]},"SmtpConfigDto":{"type":"object","properties":{"host":{"type":"string","maxLength":255},"port":{"type":"number","minimum":1,"maximum":65535},"user":{"type":"string","maxLength":255},"pass":{"type":"string","maxLength":1024},"from":{"type":"string","maxLength":320,"format":"email"}},"required":["host","port","user","pass","from"]},"EmailConfigDto":{"type":"object","properties":{"imap":{"description":"IMAP receive config","allOf":[{"$ref":"#/components/schemas/ImapConfigDto"}]},"smtp":{"description":"SMTP send config","allOf":[{"$ref":"#/components/schemas/SmtpConfigDto"}]}},"required":["imap","smtp"]},"GithubChannelConfigDto":{"type":"object","properties":{"installation_id":{"type":"number","description":"The org's GitHub App installation id this channel rides.","example":82345678},"repos":{"description":"Repo full_names to listen to. Empty/omit = all repos of the installation.","example":["calltek/kj-backend"],"type":"array","items":{"type":"string","maxLength":140}},"events":{"description":"Event types to listen to (pull_request, issues, push…). Empty/omit = all subscribed events.","example":["pull_request","pull_request_review"],"type":"array","items":{"type":"string","maxLength":60}},"listen_scope":{"enum":["all","involved"],"type":"string","description":"Listening scope, GitHub-notifications style. \"all\" (default): every event of the configured repos/events wakes the agent. \"involved\": only events that concern the agent — review requested of it, assigned to it, @-mentioned, or activity on a PR/issue it authored. Needs the agent's GitHub connector (its identity) to resolve; with no connector it falls back to \"all\" (fail-open, never a missed review).","example":"involved"},"raw_payload":{"type":"boolean","description":"Attach the full raw webhook payload to each event. Off by default: measured on production it is ~3.000 tokens per event of API template URLs and repeated user objects, for ~61 tokens of meaning — and the agent re-reads it on every step of that turn. Turn it on only for a channel whose skill genuinely parses an exotic field.","example":false}},"required":["installation_id"]},"DriveChannelConfigDto":{"type":"object","properties":{"folder_id":{"type":"string","minLength":1,"maxLength":255,"description":"Google Drive folder id to watch (from the folder picker). New or modified files in it become events for the agent.","example":"1AbCdEfGhIjKlMnOpQrStUvWxYz"},"folder_name":{"type":"string","maxLength":255,"description":"Folder display name (labels the Agent Desk thread and the event text).","example":"Facturas"}},"required":["folder_id"]},"CalendarChannelConfigDto":{"type":"object","properties":{"reminder_lead_minutes":{"type":"number","minimum":1,"maximum":1440,"description":"Optional reminder lead: the agent also gets a heads-up this many minutes before each event starts (one per occurrence). Omit/0 = changes only.","example":15}}},"CreateChannelGlobalDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"Display name for the channel","example":"Soporte Telegram"},"scope":{"enum":["EXTERNAL","INTERNAL"],"type":"string","description":"Scope. EXTERNAL (default): reaches customers, surfaces in the Agent Desk. INTERNAL: operators/rooms — never creates external contacts, never in the Agent Desk.","example":"EXTERNAL"},"direction":{"enum":["INBOUND","OUTBOUND","BIDIRECTIONAL"],"type":"string","description":"Traffic direction. BIDIRECTIONAL (default): receives and replies. INBOUND: receives only (the agent acts via tools/API, never replies down the channel). OUTBOUND: sends only, never ingests inbound (pure notifications; a WEBHOOK OUTBOUND channel requires outbound_url). Event channels (GITHUB/DRIVE/CALENDAR) are always INBOUND.","example":"BIDIRECTIONAL"},"transport":{"enum":["INTERNAL","WHATSAPP","GMAIL","DISCORD","TELEGRAM","SLACK","WEBHOOK","EMAIL","GITHUB","DRIVE","CALENDAR","HOST"],"type":"string","description":"Transport. TELEGRAM/DISCORD use a bot token; WEBHOOK uses webhook config; EMAIL uses imap/smtp config.","example":"TELEGRAM"},"bot_token":{"type":"string","minLength":10,"description":"Bot token for TELEGRAM/DISCORD/SLACK (validated against the provider and stored encrypted). Not used for WEBHOOK or EMAIL.","example":"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"},"signing_secret":{"type":"string","minLength":10,"description":"Slack app signing secret. Required for SLACK: used to verify that every inbound message really comes from Slack. Stored encrypted.","example":"your-app-signing-secret"},"destination":{"type":"string","minLength":1,"maxLength":255,"description":"Destination the agent sends to. Required for DISCORD (target text-channel / DM id). Ignored for Telegram.","example":"123456789012345678"},"connector_id":{"type":"number","minimum":1,"description":"Id of an existing GOOGLE connector for GMAIL/DRIVE/CALENDAR (from the org's connector list). Picks which of the org's Google accounts this channel operates through — and becomes the agent's active Google identity, same as PUT .../channel/:id/connector. Omit to keep the agent's current one (or connect a new account afterwards, for GMAIL).","example":4},"webhook":{"description":"WEBHOOK transport config (outbound).","allOf":[{"$ref":"#/components/schemas/WebhookConfigDto"}]},"email":{"description":"EMAIL transport config (imap + smtp).","allOf":[{"$ref":"#/components/schemas/EmailConfigDto"}]},"github":{"description":"GITHUB transport config (installation + repo/event filters).","allOf":[{"$ref":"#/components/schemas/GithubChannelConfigDto"}]},"drive":{"description":"DRIVE transport config (the folder to watch).","allOf":[{"$ref":"#/components/schemas/DriveChannelConfigDto"}]},"calendar":{"description":"CALENDAR transport config (the calendar to watch + reminder lead).","allOf":[{"$ref":"#/components/schemas/CalendarChannelConfigDto"}]},"host_id":{"type":"number","minimum":1,"description":"HOST transport: the kj-host device this «device» channel links the agent to. N channels per device (one per agent). Defaults: scope INTERNAL, direction INBOUND.","example":12},"instructions":{"type":"string","maxLength":8000,"description":"Operating instructions for an EVENT channel (WEBHOOK/GITHUB/DRIVE/CALENDAR) or a mail channel (EMAIL/GMAIL): what the agent should do with the events/emails from this channel. Injected as a <system-reminder> with every forwarded message, so it never bloats the agent's permanent context. Markdown, optional. Ignored for chat transports (Telegram/Discord act on memory).","example":"Review PRs where you are requested; approve if clean, else comment."},"agent_id":{"type":"number","minimum":1,"description":"Agent this channel belongs to","example":1}},"required":["name","transport","agent_id"]},"UpdateGithubConfigDto":{"type":"object","properties":{"repos":{"description":"Repo full_names to listen to. Empty = all repos of the installation.","example":["calltek/kj-backend"],"type":"array","items":{"type":"string","maxLength":140}},"events":{"description":"Event types to listen to. Empty = all subscribed events.","example":["pull_request","issue_comment"],"type":"array","items":{"type":"string","maxLength":60}},"listen_scope":{"enum":["all","involved"],"type":"string","description":"Listening scope: \"all\" = every event; \"involved\" = only events that concern the agent (review requested / assigned / @-mentioned / its own PRs), GitHub-notifications style.","example":"involved"},"raw_payload":{"type":"boolean","description":"Attach the full raw webhook payload to each event. Off by default: measured on production it is ~3.000 tokens per event of API template URLs and repeated user objects, for ~61 tokens of meaning — and the agent re-reads it on every step of that turn. Turn it on only for a channel whose skill genuinely parses an exotic field.","example":false}}},"UpdateChannelDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"Display name","example":"Soporte Telegram"},"scope":{"enum":["EXTERNAL","INTERNAL"],"type":"string","description":"Scope: EXTERNAL (Agent Desk-facing) or INTERNAL (operators/rooms)"},"direction":{"enum":["INBOUND","OUTBOUND","BIDIRECTIONAL"],"type":"string","description":"Traffic direction: INBOUND (receive only), OUTBOUND (send only), BIDIRECTIONAL (both). Switching a WEBHOOK to OUTBOUND requires an outbound_url. Ignored for event channels (GITHUB/DRIVE/CALENDAR), which stay INBOUND."},"bot_token":{"type":"string","minLength":10,"description":"New bot token to rotate to. Validated + stored encrypted; never returned."},"signing_secret":{"type":"string","minLength":10,"description":"New Slack signing secret. Stored encrypted and never returned. Leave empty to keep the existing one."},"mention_off":{"uniqueItems":true,"description":"Per-chat-id mention exceptions. Group chat_ids in this list opt OUT of the require-mention default — the agent answers every message in them. Send the FULL intended list (the server replaces, not merges). No effect on DMs.","type":"array","items":{"type":"string"}},"webhook":{"description":"WEBHOOK transport config. Editable in place: outbound URL/secret, inbound HMAC secret, signature header + prefix. Secrets are only rewritten when present (empty/omitted = keep the current one).","allOf":[{"$ref":"#/components/schemas/WebhookConfigDto"}]},"github":{"description":"GITHUB transport config, editable in place: the listening scope (all/involved) and the repo/event filters. Only present fields change.","allOf":[{"$ref":"#/components/schemas/UpdateGithubConfigDto"}]},"instructions":{"type":"string","maxLength":8000,"description":"Operating instructions for an EVENT channel (WEBHOOK/GITHUB/DRIVE/CALENDAR) or a mail channel (EMAIL/GMAIL), injected as a <system-reminder> with each forwarded message. A string sets it, an empty string clears it, omitting keeps the current one."},"notify_conversation_id":{"type":"number","nullable":true,"minimum":1,"description":"Escalation destination (#567): id of an INTERNAL conversation of this same agent (operator thread / internal room) where notices and approval prompts born on this channel land. Must live on a channel that can send (not inbound-only) and never on a customer thread. null clears it, omitting keeps the current one.","example":42},"is_active":{"type":"boolean","description":"Active flag. A DRIVE/CALENDAR channel the poller could not run (see inactive_reason on the channel) is set to false automatically — flip it back to true after fixing the underlying connector to resume polling; that also clears inactive_reason. Setting this to false stops the channel from ingesting or sending — it is a containment switch, not a credential revocation: it does NOT rotate webhook_secret or invalidate a Discord/Telegram bot token. If the channel was compromised (leaked secret, stolen token), delete it (or rotate the bot token) instead of just disabling it. When rotating a Discord bot token, write the new one HERE FIRST and only revoke the old one in Discord afterwards: the replica that owns the socket closes it on its next lease check because the stored token no longer matches, so rotating here is what actually kills the old connection. Revoking in Discord first still works, but the ugly way: the socket reconnects against a dead credential until Discord rejects it (close code 4004), and the channel then DEACTIVATES ITSELF with an inactive_reason — so you end up having to flip this back to true by hand after storing the new token. DISCORD takes effect within ~15s when turning off (the bot's gateway session is closed on its next lease check) and up to ~30s when turning back on (picked up by the periodic connect sweep) — other transports take effect immediately. That ~15s is only the socket teardown: containment itself is immediate on every replica — ingestion, outbound sends and HITL approval buttons all read the flag per message, so nothing gets through in the meantime. GITHUB: turning this off does not defer webhook deliveries for replay later — GitHub does not retry a webhook that got a 2xx, so events that arrive while the channel is off are dropped for good."}}},"AddToWhitelistDto":{"type":"object","properties":{"origin_id":{"type":"string","minLength":1,"maxLength":255,"description":"Origin chat/channel id to accept inbound from (Telegram chat id / Discord channel id). Added to the channel whitelist.","example":"1512401528445730899"}},"required":["origin_id"]},"CronjobAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"flex-test"}},"required":["id","name"]},"CronjobCredentialDto":{"type":"object","properties":{"id":{"type":"number","description":"Credential id","example":7},"name":{"type":"string","description":"Credential name","example":"stripe"}},"required":["id","name"]},"GetCronjobDto":{"type":"object","properties":{"id":{"type":"number","description":"Cronjob id","example":1},"organization_id":{"type":"number","description":"Organization id","example":2},"agent_id":{"type":"number","description":"Agent id","example":5},"agent":{"description":"Agent summary","allOf":[{"$ref":"#/components/schemas/CronjobAgentDto"}]},"name":{"type":"string","description":"Name","example":"daily-report"},"description":{"type":"string","nullable":true,"description":"Description"},"schedule":{"type":"string","nullable":true,"description":"Cron expression (recurring). Null on a one-shot — see run_at.","example":"0 9 * * 1"},"run_at":{"format":"date-time","type":"string","nullable":true,"description":"One-shot (KJ-190): the instant it fires. Null on a recurring cron."},"expires_at":{"format":"date-time","type":"string","nullable":true,"description":"Stop running after this instant (KJ-190). Null = no deadline."},"max_runs":{"type":"number","nullable":true,"description":"Stop after this many runs (KJ-190). Null = unlimited.","example":3},"run_count":{"type":"number","description":"Scheduled runs so far (KJ-190)","example":0},"kind":{"enum":["INPUT","SCRIPT"],"type":"string","description":"Kind","example":"INPUT"},"status":{"enum":["ACTIVE","PENDING_APPROVAL","DISABLED","EXPIRED"],"type":"string","description":"Status","example":"ACTIVE"},"enabled":{"type":"boolean","description":"Whether the schedule is active","example":true},"internal":{"type":"boolean","description":"The agent's own bookkeeping (monitor/probe): hidden from the cron list unless include_internal=true, and always carries a forced expires_at.","example":false},"message":{"type":"string","nullable":true,"description":"INPUT: injected turn text"},"command":{"type":"string","nullable":true,"description":"SCRIPT: the command"},"timeout_ms":{"type":"number","description":"SCRIPT: timeout (ms)","example":60000},"model":{"type":"string","nullable":true,"description":"INPUT: Claude model slug to run this scheduled turn on (KJ-22). Null = inherit the agent/conversation default.","example":"claude-haiku-4-5"},"report_when":{"enum":["ALWAYS","ON_CHANGE","ON_MATCH","NEVER"],"type":"string","description":"SCRIPT: when output is reported to the agent","example":"ALWAYS"},"report_pattern":{"type":"string","nullable":true,"description":"SCRIPT + ON_MATCH: regex deciding when to notify"},"notify_conversation_id":{"type":"number","nullable":true,"description":"Conversation to report to (contact + channel); null = log only"},"credentials":{"description":"Credentials injected as env vars into a SCRIPT cron (KJ-38). Names only, never values.","type":"array","items":{"$ref":"#/components/schemas/CronjobCredentialDto"}},"last_run_at":{"format":"date-time","type":"string","nullable":true,"description":"Last run timestamp"},"last_status":{"type":"string","nullable":true,"description":"Last run status"},"last_result":{"type":"object","description":"Last run result (exit_code/output for SCRIPT)","nullable":true},"created_by":{"type":"number","nullable":true,"description":"Creator user id (null for MCP/service)"},"is_mine":{"type":"boolean","description":"Whether the requesting user owns this cron (private to them)","example":true},"shared_user_ids":{"description":"User ids this cron is shared with (besides the owner)","example":[3,7],"type":"array","items":{"type":"number"}},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"timezone":{"type":"string","nullable":true}},"required":["id","organization_id","agent_id","agent","name","run_count","kind","status","enabled","internal","timeout_ms","report_when","credentials","is_mine","shared_user_ids","created_at","updated_at","timezone"]},"CronjobRunDto":{"type":"object","properties":{"id":{"type":"number","description":"Run id","example":1},"status":{"type":"string","description":"Status","example":"SUCCESS"},"exit_code":{"type":"number","nullable":true,"description":"Exit code (SCRIPT)"},"output":{"type":"string","nullable":true,"description":"Truncated stdout/stderr"},"truncated":{"type":"boolean","description":"Whether the output was truncated","example":false},"notified":{"type":"boolean","description":"Whether this run was sent to the notify channel","example":false},"duration_ms":{"type":"number","nullable":true,"description":"Wall-clock duration of the run in ms (KUJI-131). Null for legacy rows. Lets a silent script still show it ran + how long.","example":1240},"created_at":{"format":"date-time","type":"string","description":"When it ran"}},"required":["id","status","truncated","notified","created_at"]},"CreateCronjobDto":{"type":"object","properties":{"agent_id":{"type":"number","minimum":1,"description":"Agent this cronjob runs against. Must belong to the same org.","example":5},"name":{"type":"string","minLength":1,"maxLength":255,"description":"Display name (unique within the org).","example":"daily-report"},"description":{"type":"string","minLength":0,"maxLength":1024,"description":"Free-form description.","example":"Resumen de pedidos cada mañana"},"schedule":{"type":"string","minLength":1,"maxLength":128,"description":"Recurring: raw cron expression (5 fields), validated on save. Mutually exclusive with run_at — send exactly one.","example":"0 9 * * 1"},"run_at":{"type":"string","description":"One-shot (KJ-190): ISO date-time this cron fires ONCE, then expires. Mutually exclusive with schedule. Must be in the future.","example":"2026-08-12T09:00:00.000Z"},"timezone":{"type":"string","nullable":true,"description":"IANA zone the expression is read in (\"Europe/Madrid\"), so \"0 7 * * *\" means seven in the morning THERE, daylight saving included. Omitted/empty inherits the agent zone, then the organization one, then UTC.","example":"Europe/Madrid"},"expires_at":{"type":"string","description":"Stop running after this instant (KJ-190) — the cron flips to EXPIRED, keeping its history. Must be in the future.","example":"2026-09-01T00:00:00.000Z"},"max_runs":{"type":"number","minimum":1,"description":"Stop after this many runs (KJ-190). Omit for unlimited.","example":3},"kind":{"enum":["INPUT","SCRIPT"],"type":"string","description":"INPUT injects a turn into the agent; SCRIPT runs a command in its container.","example":"INPUT"},"internal":{"type":"boolean","description":"Agent bookkeeping (a monitor, a re-check, a probe): kept out of the cron list unless include_internal=true. An internal cron is ALWAYS given a deadline — the one sent, capped at 7 days, or 1 day if none — so a monitor can't outlive whatever it was watching.","example":false},"message":{"type":"string","minLength":1,"maxLength":8192,"description":"For INPUT: the text injected as a scheduled turn.","example":"Genera el reporte de ayer y avísame."},"command":{"type":"string","minLength":1,"maxLength":8192,"description":"For SCRIPT: the shell command run inside the container.","example":"python3 /home/agent/scripts/report.py"},"timeout_ms":{"type":"number","minimum":1000,"maximum":86400000,"description":"For SCRIPT: hard timeout in ms. The longest allowed is a platform setting (6 h by default); asking for more is a 400 CRONJOB_TIMEOUT_TOO_LONG.","example":60000},"report_when":{"enum":["ALWAYS","ON_CHANGE","ON_MATCH","NEVER"],"type":"string","description":"SCRIPT report gate (only applies with notify_conversation_id): ALWAYS / ON_CHANGE (output differs) / ON_MATCH (matches report_pattern) / NEVER. Failures always notify except NEVER. Ignored for INPUT.","example":"ON_CHANGE"},"report_pattern":{"type":"string","minLength":1,"maxLength":512,"description":"SCRIPT + ON_MATCH: regex; the output is reported only when it matches.","example":"\"reales61\":\\s*[1-9]"},"notify_conversation_id":{"type":"number","minimum":1,"description":"Conversation (contact + channel) to report to. SCRIPT delivers its stdout there (non-LLM); INPUT asks the agent to report there. Must be a conversation of this agent. Omit to only log.","example":7},"credential_ids":{"uniqueItems":true,"description":"SCRIPT only (KJ-38): ids of credentials to inject as env vars into the command. Each MUST be assigned to this agent. A field becomes `<CRED>_<FIELD>` (uppercased), plus a bare `<CRED>` when the credential has one field; OTP fields yield the live code. Never written to disk.","example":[7,9],"type":"array","items":{"type":"number"}},"model":{"type":"string","minLength":0,"maxLength":80,"description":"INPUT only (KJ-22): Claude model for this scheduled turn — \"haiku\"/\"sonnet\"/\"opus\" or a full claude-… slug. Routine crons run cheaper. Empty/omitted = inherit the default.","example":"haiku"}},"required":["agent_id","name","kind"]},"UpdateCronjobDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"Display name.","example":"daily-report"},"description":{"type":"string","minLength":0,"maxLength":1024,"description":"Free-form description."},"schedule":{"type":"string","minLength":0,"maxLength":128,"description":"Raw cron expression. Send \"\" (empty) together with run_at to turn a recurring cron into a one-shot.","example":"0 9 * * 1"},"run_at":{"type":"string","nullable":true,"description":"One-shot instant (KJ-190), ISO date-time. Null clears it. Setting it re-arms an already-fired one-shot.","example":"2026-08-12T09:00:00.000Z"},"timezone":{"type":"string","nullable":true,"description":"IANA zone the expression is read in (\"Europe/Madrid\"), so \"0 7 * * *\" means seven in the morning THERE, daylight saving included. Empty inherits the agent zone, then the organization one, then UTC.","example":"Europe/Madrid"},"expires_at":{"type":"string","nullable":true,"description":"Stop running after this instant (KJ-190). Null clears the deadline."},"max_runs":{"type":"number","nullable":true,"minimum":1,"description":"Stop after this many runs (KJ-190). Null = unlimited.","example":3},"enabled":{"type":"boolean","description":"Enable/disable the schedule.","example":true},"internal":{"type":"boolean","description":"Mark/unmark as agent bookkeeping (hidden from the list by default). While internal, the cron's deadline is re-capped on every save — you cannot park an internal cron forever by clearing expires_at.","example":false},"message":{"type":"string","minLength":1,"maxLength":8192,"description":"For INPUT: the injected turn text."},"command":{"type":"string","minLength":1,"maxLength":8192,"description":"For SCRIPT: the command."},"timeout_ms":{"type":"number","minimum":1000,"maximum":86400000,"description":"For SCRIPT: timeout in ms. The longest allowed is a platform setting (6 h by default)."},"report_when":{"enum":["ALWAYS","ON_CHANGE","ON_MATCH","NEVER"],"type":"string","description":"SCRIPT report gate (with notify_conversation_id): ALWAYS | ON_CHANGE | ON_MATCH | NEVER."},"report_pattern":{"type":"string","minLength":0,"maxLength":512,"description":"SCRIPT + ON_MATCH: regex; output is reported only when it matches."},"notify_conversation_id":{"type":"number","nullable":true,"minimum":1,"description":"Conversation to report to (contact + channel). null clears it."},"credential_ids":{"uniqueItems":true,"description":"SCRIPT only (KJ-38): replace the set of credentials injected as env vars. Each MUST be assigned to this agent. [] clears them.","example":[7,9],"type":"array","items":{"type":"number"}},"model":{"type":"string","minLength":0,"maxLength":80,"description":"INPUT only (KJ-22): model for this scheduled turn (\"haiku\"/\"sonnet\"/\"opus\" or a claude-… slug). Empty string clears it (inherit).","example":"haiku"}}},"McpAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"}},"required":["id","name"]},"GetMcpDto":{"type":"object","properties":{"id":{"type":"number","description":"MCP server id","example":1},"name":{"type":"string","description":"Slug name — the key in the .mcp.json mcpServers object.","example":"github"},"description":{"type":"string","description":"One-line summary.","example":"Lee repos, crea issues"},"transport":{"enum":["STDIO","SSE","HTTP"],"type":"string","description":"Transport","example":"STDIO"},"command":{"type":"string","nullable":true,"description":"STDIO command"},"args":{"description":"STDIO argv","type":"array","items":{"type":"string"}},"url":{"type":"string","nullable":true,"description":"SSE/HTTP endpoint"},"auth":{"description":"Names of the env vars configured on this server (the \"auth\" the agent gets). Values are NEVER returned — they live encrypted at rest.","example":["GITHUB_TOKEN"],"type":"array","items":{"type":"string"}},"assignment_count":{"type":"number","description":"Number of agents this server is assigned to. Zero = unassigned.","example":3},"agents":{"description":"Agents this server is assigned to (id, name, avatar). Enough to render them on a list row — the full assignment records come with the detail endpoint.","type":"array","items":{"$ref":"#/components/schemas/McpAgentDto"}},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When the server was archived (soft-deleted). Null on live servers. Archived servers are excluded from default listings and never shipped in a spawn payload."}},"required":["id","name","description","transport","args","auth","assignment_count","agents","created_at","updated_at"]},"ListMcpDto":{"type":"object","properties":{"rows":{"description":"Page rows","type":"array","items":{"$ref":"#/components/schemas/GetMcpDto"}},"total":{"type":"number","description":"Total matching rows across all pages","example":23},"limit":{"type":"number","description":"Echo of the requested page size","example":50},"offset":{"type":"number","description":"Echo of the requested offset","example":0}},"required":["rows","total","limit","offset"]},"McpAssignedAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"},"assigned_at":{"format":"date-time","type":"string","description":"When the server was assigned to this agent"}},"required":["id","name","assigned_at"]},"GetMcpWithAssignmentsDto":{"type":"object","properties":{"id":{"type":"number","description":"MCP server id","example":1},"name":{"type":"string","description":"Slug name — the key in the .mcp.json mcpServers object.","example":"github"},"description":{"type":"string","description":"One-line summary.","example":"Lee repos, crea issues"},"transport":{"enum":["STDIO","SSE","HTTP"],"type":"string","description":"Transport","example":"STDIO"},"command":{"type":"string","nullable":true,"description":"STDIO command"},"args":{"description":"STDIO argv","type":"array","items":{"type":"string"}},"url":{"type":"string","nullable":true,"description":"SSE/HTTP endpoint"},"auth":{"description":"Names of the env vars configured on this server (the \"auth\" the agent gets). Values are NEVER returned — they live encrypted at rest.","example":["GITHUB_TOKEN"],"type":"array","items":{"type":"string"}},"assignment_count":{"type":"number","description":"Number of agents this server is assigned to. Zero = unassigned.","example":3},"agents":{"description":"Agents this server is assigned to (id, name, avatar). Enough to render them on a list row — the full assignment records come with the detail endpoint.","type":"array","items":{"$ref":"#/components/schemas/McpAgentDto"}},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When the server was archived (soft-deleted). Null on live servers. Archived servers are excluded from default listings and never shipped in a spawn payload."},"assignments":{"description":"Agents this server is currently assigned to","type":"array","items":{"$ref":"#/components/schemas/McpAssignedAgentDto"}}},"required":["id","name","description","transport","args","auth","assignment_count","agents","created_at","updated_at","assignments"]},"CreateMcpDto":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":255,"description":"Slug name. Lowercase letters, digits, hyphens, underscores. Becomes the key in the .mcp.json mcpServers object.","example":"github"},"description":{"type":"string","minLength":1,"maxLength":512,"description":"One-line summary shown in the operator panel.","example":"Lee repos, crea issues, comenta PRs"},"transport":{"enum":["STDIO","SSE","HTTP"],"type":"string","description":"Transport the server speaks. STDIO = local process (command + args). SSE/HTTP = remote endpoint (url).","example":"STDIO"},"command":{"type":"string","minLength":1,"maxLength":512,"description":"STDIO only: the executable to run.","example":"npx"},"args":{"description":"STDIO only: argv passed to the command.","example":["-y","@modelcontextprotocol/server-github"],"type":"array","items":{"type":"string"}},"url":{"type":"string","format":"uri","minLength":1,"maxLength":1024,"description":"SSE/HTTP only: the server endpoint.","example":"https://mcp.notion.com/v1"},"env":{"type":"object","additionalProperties":{"type":"string"},"description":"Env vars to inject into the server process, as a name→value map. Values are encrypted at rest and never returned. The GET DTO exposes only the names (auth).","example":{"GITHUB_TOKEN":"ghp_xxx"}}},"required":["name","description","transport"]},"UpdateMcpDto":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":255,"description":"New slug name. Optional.","example":"github"},"description":{"type":"string","minLength":1,"maxLength":512,"description":"New one-line summary. Optional."},"transport":{"enum":["STDIO","SSE","HTTP"],"type":"string","description":"New transport. Optional."},"command":{"type":"string","minLength":1,"maxLength":512,"description":"STDIO command. Optional."},"args":{"description":"STDIO argv. Optional.","type":"array","items":{"type":"string"}},"url":{"type":"string","minLength":1,"maxLength":1024,"description":"SSE/HTTP endpoint. Optional."},"env":{"type":"object","additionalProperties":{"type":"string"},"description":"Replace the env var set entirely. name→value map; values encrypted at rest. Omit to leave the current env untouched; pass {} to clear it.","example":{"GITHUB_TOKEN":"ghp_xxx"}}}},"SetMcpAgentsDto":{"type":"object","properties":{"agent_ids":{"uniqueItems":true,"description":"Full list of agents this server should be assigned to. The service syncs: new ids are added, missing ids removed. Pass [] to detach from every agent.","example":[3,5],"type":"array","items":{"type":"number","minimum":1}}},"required":["agent_ids"]},"CredentialAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"}},"required":["id","name"]},"GetCredentialDto":{"type":"object","properties":{"id":{"type":"number","description":"Credential id","example":1},"name":{"type":"string","description":"Unique name per org","example":"STRIPE_SECRET"},"description":{"type":"string","nullable":true,"description":"Description"},"kind":{"type":"string","nullable":true,"description":"Free-form kind for the UI"},"destinations":{"description":"Where this credential is meant to be used. Empty = not set.","type":"array","items":{"type":"string"}},"assignment_count":{"type":"number","description":"Number of agents this credential is assigned to. Zero = unassigned.","example":3},"agents":{"description":"Agents this credential is assigned to (id, name, avatar). Enough to render them on a list row — the full assignment records, with who granted them and when, come with the detail endpoint.","type":"array","items":{"$ref":"#/components/schemas/CredentialAgentDto"}},"field_count":{"type":"number","description":"Number of fields","example":2},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When archived (soft-deleted). Null on live credentials."}},"required":["id","name","destinations","assignment_count","agents","field_count","created_at","updated_at"]},"ListCredentialDto":{"type":"object","properties":{"rows":{"description":"Page rows","type":"array","items":{"$ref":"#/components/schemas/GetCredentialDto"}},"total":{"type":"number","description":"Total matching rows across all pages","example":47},"limit":{"type":"number","description":"Echo of the requested page size","example":50},"offset":{"type":"number","description":"Echo of the requested offset","example":0}},"required":["rows","total","limit","offset"]},"CredentialFieldDto":{"type":"object","properties":{"id":{"type":"number","description":"Field id","example":10},"label":{"type":"string","description":"Field label","example":"api_key"},"type":{"enum":["TEXT","USERNAME","PASSWORD","EMAIL","URL","API_KEY","OTP","NOTE","SSH_PRIVATE_KEY","SSH_PUBLIC_KEY"],"type":"string","description":"Field type"},"position":{"type":"number","description":"Display order","example":0},"has_value":{"type":"boolean","description":"Whether a value is set. The value itself is never returned here.","example":true}},"required":["id","label","type","position","has_value"]},"CredentialAssignedAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"},"assigned_at":{"format":"date-time","type":"string","description":"When the credential was assigned to this agent"}},"required":["id","name","assigned_at"]},"CredentialMemberDto":{"type":"object","properties":{"user_id":{"type":"number","description":"User id","example":7},"name":{"type":"string","description":"User name","example":"Ana"},"email":{"type":"string","description":"User email","example":"ana@acme.com"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"},"granted_at":{"format":"date-time","type":"string","description":"When access was granted"}},"required":["user_id","name","email","granted_at"]},"GetCredentialWithFieldsDto":{"type":"object","properties":{"id":{"type":"number","description":"Credential id","example":1},"name":{"type":"string","description":"Unique name per org","example":"STRIPE_SECRET"},"description":{"type":"string","nullable":true,"description":"Description"},"kind":{"type":"string","nullable":true,"description":"Free-form kind for the UI"},"destinations":{"description":"Where this credential is meant to be used. Empty = not set.","type":"array","items":{"type":"string"}},"assignment_count":{"type":"number","description":"Number of agents this credential is assigned to. Zero = unassigned.","example":3},"agents":{"description":"Agents this credential is assigned to (id, name, avatar). Enough to render them on a list row — the full assignment records, with who granted them and when, come with the detail endpoint.","type":"array","items":{"$ref":"#/components/schemas/CredentialAgentDto"}},"field_count":{"type":"number","description":"Number of fields","example":2},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When archived (soft-deleted). Null on live credentials."},"fields":{"description":"Fields (label + type only, no values)","type":"array","items":{"$ref":"#/components/schemas/CredentialFieldDto"}},"assignments":{"description":"Agents this credential is assigned to","type":"array","items":{"$ref":"#/components/schemas/CredentialAssignedAgentDto"}},"members":{"description":"Operators allowed to reveal this credential. Empty = open (any member with credential.reveal); non-empty = only these (plus OWNER/ADMIN).","type":"array","items":{"$ref":"#/components/schemas/CredentialMemberDto"}}},"required":["id","name","destinations","assignment_count","agents","field_count","created_at","updated_at","fields","assignments","members"]},"RevealCredentialFieldDto":{"type":"object","properties":{"id":{"type":"number","description":"Field id","example":10},"label":{"type":"string","description":"Field label","example":"api_key"},"type":{"enum":["TEXT","USERNAME","PASSWORD","EMAIL","URL","API_KEY","OTP","NOTE","SSH_PRIVATE_KEY","SSH_PUBLIC_KEY"],"type":"string","description":"Field type"},"value":{"type":"string","description":"Decrypted plaintext value"}},"required":["id","label","type","value"]},"CredentialFieldInput":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":255,"description":"Field label, e.g. \"username\", \"api_key\", \"host\"."},"type":{"enum":["TEXT","USERNAME","PASSWORD","EMAIL","URL","API_KEY","OTP","NOTE","SSH_PRIVATE_KEY","SSH_PUBLIC_KEY"],"type":"string","description":"Field type"},"value":{"type":"string","minLength":0,"maxLength":20000,"description":"Plaintext value. Encrypted server-side, never returned."},"position":{"type":"number","minimum":0,"description":"Display order (0-based)."}},"required":["label","type","value"]},"CreateCredentialDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"Unique name per org. Letters, digits, . _ -","example":"STRIPE_SECRET"},"description":{"type":"string","minLength":0,"maxLength":512,"description":"One-line description."},"kind":{"type":"string","minLength":0,"maxLength":64,"description":"Free-form kind for the UI icon/summary (login / api-key / database …).","example":"api-key"},"destinations":{"description":"Where this credential is meant to be used: URLs, IPs or host names. The agent receives them and knows where the key belongs. Empty = not set, which blocks nothing.","example":["https://api.stripe.com","dashboard.stripe.com"],"type":"array","items":{"type":"string"}},"fields":{"description":"The credential fields.","type":"array","items":{"$ref":"#/components/schemas/CredentialFieldInput"}}},"required":["name","fields"]},"UpdateCredentialDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"New name. Optional."},"description":{"type":"string","minLength":0,"maxLength":512,"description":"New description. Optional."},"kind":{"type":"string","minLength":0,"maxLength":64,"description":"New kind. Optional."},"destinations":{"description":"Replace the full list of destinations. Omit to leave it untouched; pass [] to clear it.","type":"array","items":{"type":"string"}},"fields":{"description":"Replace the full set of fields. Omit to leave fields untouched; pass [] to clear them. Each entry is the plaintext field; values are re-encrypted.","type":"array","items":{"$ref":"#/components/schemas/CredentialFieldInput"}}}},"SetCredentialAgentsDto":{"type":"object","properties":{"agent_ids":{"uniqueItems":true,"description":"Full list of agents this credential should be assigned to. The service syncs: new ids are added, missing ids removed. Pass [] to detach from every agent.","example":[3,5],"type":"array","items":{"type":"number","minimum":1}}},"required":["agent_ids"]},"GetSkillDto":{"type":"object","properties":{"id":{"type":"number","description":"Skill id","example":1},"name":{"type":"string","description":"Slug name — becomes the directory under /home/agent/.claude/skills/<name>/","example":"code-review"},"description":{"type":"string","description":"One-line summary, mirrored into the SKILL.md frontmatter description.","example":"Review a diff for correctness and style."},"model":{"type":"string","nullable":true,"description":"Per-skill model override (SKILL.md frontmatter `model:`). Null = inherit the agent spawn model.","example":"claude-haiku-4-5"},"effort":{"nullable":true,"enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"],"type":"string","description":"Per-skill effort override (SKILL.md frontmatter `effort:`). Null = inherit the session effort. One of LOW|MEDIUM|HIGH|XHIGH|MAX.","example":"LOW"},"content_hash":{"type":"string","description":"SHA-256 of `content`, lets the supervisor skip a no-op rewrite"},"assignment_count":{"type":"number","description":"Number of agents this skill is assigned to. Zero = unassigned.","example":3},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When the skill was archived (soft-deleted). Null on live skills. Archived skills are excluded from default listings and never seeded to a container volume."}},"required":["id","name","description","content_hash","assignment_count","created_at","updated_at"]},"ListSkillDto":{"type":"object","properties":{"rows":{"description":"Page rows","type":"array","items":{"$ref":"#/components/schemas/GetSkillDto"}},"total":{"type":"number","description":"Total matching rows across all pages","example":31},"limit":{"type":"number","description":"Echo of the requested page size","example":50},"offset":{"type":"number","description":"Echo of the requested offset","example":0}},"required":["rows","total","limit","offset"]},"SkillAssignedAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"},"assigned_at":{"format":"date-time","type":"string","description":"When the skill was assigned to this agent"}},"required":["id","name","assigned_at"]},"GetSkillWithContentDto":{"type":"object","properties":{"id":{"type":"number","description":"Skill id","example":1},"name":{"type":"string","description":"Slug name — becomes the directory under /home/agent/.claude/skills/<name>/","example":"code-review"},"description":{"type":"string","description":"One-line summary, mirrored into the SKILL.md frontmatter description.","example":"Review a diff for correctness and style."},"model":{"type":"string","nullable":true,"description":"Per-skill model override (SKILL.md frontmatter `model:`). Null = inherit the agent spawn model.","example":"claude-haiku-4-5"},"effort":{"nullable":true,"enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"],"type":"string","description":"Per-skill effort override (SKILL.md frontmatter `effort:`). Null = inherit the session effort. One of LOW|MEDIUM|HIGH|XHIGH|MAX.","example":"LOW"},"content_hash":{"type":"string","description":"SHA-256 of `content`, lets the supervisor skip a no-op rewrite"},"assignment_count":{"type":"number","description":"Number of agents this skill is assigned to. Zero = unassigned.","example":3},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When the skill was archived (soft-deleted). Null on live skills. Archived skills are excluded from default listings and never seeded to a container volume."},"content":{"type":"string","description":"Markdown body of the SKILL.md (without frontmatter)"},"assignments":{"description":"Agents this skill is currently assigned to","type":"array","items":{"$ref":"#/components/schemas/SkillAssignedAgentDto"}}},"required":["id","name","description","content_hash","assignment_count","created_at","updated_at","content","assignments"]},"GetSkillEntryDto":{"type":"object","properties":{"path":{"type":"string","description":"Path inside the skill folder.","example":"references/api.md"},"size":{"type":"number","description":"Size in bytes (utf-8).","example":1024},"content_hash":{"type":"string","description":"sha256 of the content."},"updated_at":{"type":"string","description":"Last write, ISO-8601."}},"required":["path","size","content_hash","updated_at"]},"GetSkillEntryContentDto":{"type":"object","properties":{"path":{"type":"string","description":"Path inside the skill folder.","example":"references/api.md"},"size":{"type":"number","description":"Size in bytes (utf-8).","example":1024},"content_hash":{"type":"string","description":"sha256 of the content."},"updated_at":{"type":"string","description":"Last write, ISO-8601."},"content":{"type":"string","description":"The file itself (utf-8 text)."}},"required":["path","size","content_hash","updated_at","content"]},"PutSkillEntryDto":{"type":"object","properties":{"path":{"type":"string","minLength":1,"maxLength":255,"description":"Path inside the skill folder. Relative, letters/digits/dot/dash/underscore only, up to 6 levels. SKILL.md is the skill body and is edited from the skill itself.","example":"references/api.md"},"content":{"type":"string","minLength":0,"maxLength":200000,"description":"The file itself (utf-8 text)."}},"required":["path","content"]},"CreateSkillDto":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":255,"description":"Slug name. Lowercase letters, digits, hyphens. Becomes the directory under /home/agent/.claude/skills/<name>/.","example":"code-review"},"description":{"type":"string","minLength":1,"maxLength":512,"description":"One-line summary (mirrored into SKILL.md frontmatter description).","example":"Review a diff for correctness and style."},"content":{"type":"string","minLength":0,"maxLength":200000,"description":"Markdown body of the SKILL.md (without frontmatter).","example":"# Code review\n\nWhen asked to review…"},"model":{"type":"string","minLength":0,"maxLength":64,"description":"Optional per-skill model override → SKILL.md frontmatter `model:`. When the skill is active the agent switches model for the rest of the turn. Null/omit = inherit the agent spawn model.","example":"claude-haiku-4-5"},"effort":{"enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"],"type":"string","description":"Optional per-skill effort override → SKILL.md frontmatter `effort:`. Same \"rest of the turn\" semantics as model. Omit = inherit the session effort.","example":"LOW"},"force":{"type":"boolean","description":"Override the credential-in-content check (#309). When the detector flags a likely API key / PEM / connection string, the save is rejected with a 400 — pass `force: true` only if you know the match is an example, not a real secret. The detector still audits the attempt either way.","example":false}},"required":["name","description","content"]},"ImportSkillFromGitDto":{"type":"object","properties":{"url":{"type":"string","format":"uri","minLength":1,"maxLength":2048,"description":"A github.com URL: the repo root, or a /tree/<ref>/<folder> (or /blob/.../SKILL.md) pointing at the folder that holds SKILL.md.","example":"https://github.com/anthropics/skills/tree/main/pdf"},"name":{"type":"string","minLength":2,"maxLength":255,"description":"Slug name for the new skill. Defaults to the repo/folder name.","example":"pdf-editing"}},"required":["url"]},"ImportedSkillDto":{"type":"object","properties":{"id":{"type":"number","description":"Skill id","example":1},"name":{"type":"string","description":"Slug name — becomes the directory under /home/agent/.claude/skills/<name>/","example":"code-review"},"description":{"type":"string","description":"One-line summary, mirrored into the SKILL.md frontmatter description.","example":"Review a diff for correctness and style."},"model":{"type":"string","nullable":true,"description":"Per-skill model override (SKILL.md frontmatter `model:`). Null = inherit the agent spawn model.","example":"claude-haiku-4-5"},"effort":{"nullable":true,"enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"],"type":"string","description":"Per-skill effort override (SKILL.md frontmatter `effort:`). Null = inherit the session effort. One of LOW|MEDIUM|HIGH|XHIGH|MAX.","example":"LOW"},"content_hash":{"type":"string","description":"SHA-256 of `content`, lets the supervisor skip a no-op rewrite"},"assignment_count":{"type":"number","description":"Number of agents this skill is assigned to. Zero = unassigned.","example":3},"created_by":{"type":"number","nullable":true,"description":"Creator user id"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"When the skill was archived (soft-deleted). Null on live skills. Archived skills are excluded from default listings and never seeded to a container volume."},"content":{"type":"string","description":"Markdown body of the SKILL.md (without frontmatter)"},"assignments":{"description":"Agents this skill is currently assigned to","type":"array","items":{"$ref":"#/components/schemas/SkillAssignedAgentDto"}},"entries":{"description":"Support files that came with the SKILL.md.","type":"array","items":{"$ref":"#/components/schemas/GetSkillEntryDto"}},"skipped":{"description":"Files in the source folder that were left out, and why (not text, too large, bad path).","example":["assets/logo.png (not text)"],"type":"array","items":{"type":"string"}}},"required":["id","name","description","content_hash","assignment_count","created_at","updated_at","content","assignments","entries","skipped"]},"UpdateSkillDto":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":255,"description":"New slug name (renames the skill directory). Optional.","example":"code-review"},"description":{"type":"string","minLength":1,"maxLength":512,"description":"New one-line summary. Optional."},"content":{"type":"string","minLength":0,"maxLength":200000,"description":"New markdown body. Optional."},"model":{"type":"string","minLength":0,"maxLength":64,"description":"Per-skill model override → SKILL.md frontmatter `model:`. Empty string clears it (inherit spawn model). Optional.","example":"claude-haiku-4-5"},"effort":{"type":"string","enum":["LOW","MEDIUM","HIGH","XHIGH","MAX"],"description":"Per-skill effort override → SKILL.md frontmatter `effort:`. Pass an empty string to clear it. Optional."},"force":{"type":"boolean","description":"Override the credential-in-content check (#309). When the detector flags a likely API key / PEM / connection string, the save is rejected with a 400 — pass `force: true` only if you know the match is an example, not a real secret. The detector still audits the attempt either way.","example":false}}},"SetSkillAgentsDto":{"type":"object","properties":{"agent_ids":{"uniqueItems":true,"description":"Full list of agents this skill should be assigned to. The service syncs: new ids are added, missing ids are removed. Pass [] to detach the skill from every agent.","example":[3,5],"type":"array","items":{"type":"number","minimum":1}}},"required":["agent_ids"]},"GetModelDto":{"type":"object","properties":{"id":{"type":"number","description":"Model id","example":1},"slug":{"type":"string","description":"Exact model id passed to `claude --model`.","example":"claude-opus-4-8"},"label":{"type":"string","description":"Pretty name shown in the picker.","example":"Opus 4.8 (1M context)"},"sort_order":{"type":"number","description":"Sort order (lower first).","example":10},"active":{"type":"boolean","description":"Whether the model is offered in the picker.","example":true},"provider":{"type":"string","description":"Provider key — which LLM provider serves this model (KUJI-67).","example":"anthropic"},"family":{"type":"string","nullable":true,"description":"Pricing-family key (null = derived from the slug).","example":"opus"},"supports_manual_thinking":{"type":"boolean","description":"Whether this model still uses the manual --thinking on/off toggle. False = reasons adaptively and is driven by --effort (the whole current catalogue); true only for legacy models (Opus 4.5 and earlier). Drives whether the UI shows the thinking control.","example":false},"price_input":{"type":"number","nullable":true,"description":"Price in USD per MILLION input tokens. Null = fall back to the built-in family table. These are COST prices, with no markup.","example":5},"price_output":{"type":"number","nullable":true,"description":"Price in USD per million output tokens. Null = family table.","example":25},"price_cache_read":{"type":"number","nullable":true,"description":"Price in USD per million tokens READ from cache. Null = family table.","example":0.5},"price_cache_write_5m":{"type":"number","nullable":true,"description":"Price per million tokens WRITTEN to the 5-minute cache. Null = family table.","example":6.25},"price_cache_write_1h":{"type":"number","nullable":true,"description":"Price per million tokens WRITTEN to the 1-hour cache. Null = family table.","example":10},"context_window":{"type":"number","nullable":true,"description":"Context window in tokens. Null = derived from the slug by the built-in heuristic.","example":1000000},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"}},"required":["id","slug","label","sort_order","active","provider","supports_manual_thinking","price_input","price_output","price_cache_read","price_cache_write_5m","price_cache_write_1h","context_window","created_at","updated_at"]},"GetGatewayModelDto":{"type":"object","properties":{"id":{"type":"string","description":"Exact model id to store in the connection.","example":"anthropic/claude-opus-5"},"label":{"type":"string","description":"The gateway's own name for it.","example":"Anthropic: Claude Opus 5"},"context_window":{"type":"number","description":"Input tokens the model's default route holds, as published by the gateway. This is what Kujira uses instead of asking the operator for it.","example":1000000}},"required":["id","label","context_window"]},"GetBackupDto":{"type":"object","properties":{"id":{"type":"number"},"agent_id":{"type":"number"},"agent_name":{"type":"string"},"status":{"enum":["PENDING","FAILED","UPLOADING","COMPLETED"],"type":"string"},"kind":{"enum":["MANUAL","SCHEDULED","PRE_MIGRATION"],"type":"string"},"size_bytes":{"type":"string","nullable":true},"error":{"type":"string","nullable":true},"created_at":{"format":"date-time","type":"string"},"completed_at":{"format":"date-time","type":"string","nullable":true},"object":{"enum":["PRESENT","MISSING","UNKNOWN"],"type":"string"}},"required":["id","agent_id","status","kind","size_bytes","error","created_at","completed_at","object"]},"SetBackupDestinationDto":{"type":"object","properties":{"endpoint":{"type":"string","maxLength":512,"format":"uri","description":"S3-compatible endpoint of the bucket"},"bucket":{"type":"string","minLength":1,"maxLength":255,"description":"Bucket name"},"region":{"type":"string","maxLength":64,"description":"Region. Empty means `auto`, which is what R2 requires."},"access_key_id":{"type":"string","minLength":1,"maxLength":255,"description":"Access key id"},"secret_access_key":{"type":"string","minLength":1,"description":"Secret access key. Stored encrypted, never returned."},"prefix":{"type":"string","maxLength":255,"description":"Optional key prefix inside the bucket"}},"required":["endpoint","bucket","access_key_id","secret_access_key"]},"GetAuditDto":{"type":"object","properties":{"id":{"type":"number","description":"Entry id","example":1},"actor_kind":{"enum":["HUMAN","AGENT","SERVICE","SYSTEM"],"type":"string","description":"Actor kind"},"actor_id":{"type":"number","nullable":true,"description":"Actor id (user/agent), null for SYSTEM"},"actor_label":{"type":"string","nullable":true,"description":"Denormalized actor label (email / agent name)"},"actor_name":{"type":"string","nullable":true,"description":"The actor's CURRENT display name (user name / agent name), resolved at read time. Null for SERVICE/SYSTEM, or when the user/agent no longer exists — fall back to actor_label."},"actor_avatar_url":{"type":"string","nullable":true,"description":"The actor's current avatar URL (user or agent), when it has one."},"action":{"type":"string","description":"Action, \"resource.verb\"","example":"credential.reveal"},"resource_type":{"type":"string","description":"Resource type","example":"credential"},"resource_id":{"type":"number","nullable":true,"description":"Resource id"},"result":{"enum":["SUCCESS","FAILURE"],"type":"string","description":"Result"},"meta":{"type":"object","additionalProperties":true,"nullable":true,"description":"Non-sensitive context (NEVER secrets)"},"created_at":{"format":"date-time","type":"string","description":"When the action happened"}},"required":["id","actor_kind","action","resource_type","result","created_at"]},"ListAuditDto":{"type":"object","properties":{"rows":{"description":"The entries (most recent first)","type":"array","items":{"$ref":"#/components/schemas/GetAuditDto"}},"total":{"type":"number","description":"Total matching the filters (ignoring pagination)"},"limit":{"type":"number","description":"Applied page size"},"offset":{"type":"number","description":"Applied offset"}},"required":["rows","total","limit","offset"]},"BillingSubscriptionDto":{"type":"object","properties":{"status":{"nullable":true,"enum":["TRIALING","ACTIVE","PAST_DUE","CANCELED","ENDED"],"type":"string","description":"Subscription state, or null when there has never been one."},"contracted_agents":{"type":"number","nullable":true,"description":"How many agents are contracted. Set by the team, so it holds even with no card payment.","example":3},"current_period_end":{"type":"string","nullable":true,"description":"When it renews (or when what was paid for runs out)."},"cancel_at_period_end":{"type":"boolean","description":"Whether cancellation is already scheduled for the end of the period.","example":false},"has_customer":{"type":"boolean","description":"Whether this organization has a customer record at the gateway. It is what decides if the customer portal can be opened: no record, nothing to manage.","example":true},"trial_ends_at":{"type":"string","nullable":true,"description":"When the trial ends, if there is one. It lives here and not on the organization so the screen has everything in one place."},"granted":{"type":"boolean","description":"The plan was agreed by hand, not bought by card (ENTERPRISE, or granted by the team). Whoever has one is not shown tariffs: their price was agreed apart.","example":false}},"required":["cancel_at_period_end","has_customer","granted"]},"BillingSummaryDto":{"type":"object","properties":{"plan":{"enum":["FREE","BASIC","PRO","ENTERPRISE"],"type":"string","description":"Organization plan"},"agent_count":{"type":"number","description":"Number of agents in the org","example":3},"subscription":{"description":"Payment state: what is contracted and how the gateway stands.","allOf":[{"$ref":"#/components/schemas/BillingSubscriptionDto"}]}},"required":["plan","agent_count","subscription"]},"ContractedAgentsDto":{"type":"object","properties":{"contracted":{"type":"number","nullable":true,"description":"Agents the organization can have right now. This is the number that decides whether another one can be created.","example":3},"in_use":{"type":"number","description":"Agents that already exist, running or not.","example":3},"running":{"type":"number","description":"Agents that are running, which are the ones that take up a slot.","example":2},"min":{"type":"number","description":"Minimum amount it can be lowered to: the agents that are running, and never less than one.","example":2},"max":{"type":"number","description":"Maximum amount the plan allows.","example":50},"paid_for":{"type":"number","nullable":true,"description":"Agents charged at the gateway. May run ahead of the contracted number for the seconds it takes the payment notification to arrive.","example":4},"period_end":{"format":"date-time","type":"string","nullable":true,"description":"When the subscription renews, which is also when a scheduled reduction takes effect.","example":"2026-09-28T10:00:00.000Z"},"scheduled":{"type":"number","nullable":true,"description":"Reduction already scheduled for the renewal, if any.","example":2},"settling":{"type":"boolean","description":"The charge has already gone through and the contracted number does not reflect it yet. Check again in a few seconds.","example":false},"can_change":{"type":"boolean","description":"Whether the amount can be changed from the panel.","example":true},"blocked_reason":{"nullable":true,"enum":["gateway_not_configured","not_billed","plan_not_sold_by_card","no_subscription","subscription_not_current"],"type":"string","description":"Why it cannot be changed, when it cannot.","example":"no_subscription"}},"required":["contracted","in_use","running","min","max","paid_for","period_end","scheduled","settling","can_change","blocked_reason"]},"CostFiguresDto":{"type":"object","properties":{"cost_micro":{"type":"string","description":"Cost in 1e-6 currency units.","example":"5000000"},"input_tokens":{"type":"string","description":"Input (uncached) tokens.","example":"120000"},"output_tokens":{"type":"string","description":"Output tokens.","example":"34000"},"cache_read_tokens":{"type":"string","description":"Cache-read tokens.","example":"900000"},"cache_write_tokens":{"type":"string","description":"Cache-write (creation) tokens.","example":"45000"},"total_tokens":{"type":"string","description":"Total tokens (sum of the four above).","example":"1099000"}},"required":["cost_micro","input_tokens","output_tokens","cache_read_tokens","cache_write_tokens","total_tokens"]},"CostSeriesPointDto":{"type":"object","properties":{"cost_micro":{"type":"string","description":"Cost in 1e-6 currency units.","example":"5000000"},"input_tokens":{"type":"string","description":"Input (uncached) tokens.","example":"120000"},"output_tokens":{"type":"string","description":"Output tokens.","example":"34000"},"cache_read_tokens":{"type":"string","description":"Cache-read tokens.","example":"900000"},"cache_write_tokens":{"type":"string","description":"Cache-write (creation) tokens.","example":"45000"},"total_tokens":{"type":"string","description":"Total tokens (sum of the four above).","example":"1099000"},"bucket":{"type":"string","description":"Bucket start (ISO date, UTC).","example":"2026-06-18T00:00:00.000Z"}},"required":["cost_micro","input_tokens","output_tokens","cache_read_tokens","cache_write_tokens","total_tokens","bucket"]},"CostBreakdownRowDto":{"type":"object","properties":{"cost_micro":{"type":"string","description":"Cost in 1e-6 currency units.","example":"5000000"},"input_tokens":{"type":"string","description":"Input (uncached) tokens.","example":"120000"},"output_tokens":{"type":"string","description":"Output tokens.","example":"34000"},"cache_read_tokens":{"type":"string","description":"Cache-read tokens.","example":"900000"},"cache_write_tokens":{"type":"string","description":"Cache-write (creation) tokens.","example":"45000"},"total_tokens":{"type":"string","description":"Total tokens (sum of the four above).","example":"1099000"},"key":{"type":"string","description":"Stable key for the dimension value.","example":"10"},"label":{"type":"string","description":"Human label for the dimension value.","example":"Ailfred"},"agent_id":{"type":"number","nullable":true,"description":"Owning agent id (channel breakdown only; null otherwise). Lets the UI show the agent's avatar.","example":7},"transport":{"type":"string","nullable":true,"description":"Channel transport (channel/conversation breakdown; null otherwise). Lets the UI show the brand logo.","example":"TELEGRAM"},"contact_name":{"type":"string","nullable":true,"description":"Contact name (conversation breakdown only; null otherwise). Seeds the contact's avatar.","example":"Soki"},"person_kind":{"type":"string","nullable":true,"description":"Contact kind (conversation breakdown): EXTERNAL | INTERNAL_USER | INTERNAL_ROOM.","example":"INTERNAL_USER"},"person_avatar_url":{"type":"string","nullable":true,"description":"Real avatar URL of the linked operator (conversation breakdown, INTERNAL_USER with a photo). Null → UI uses the generative avatar.","example":"/user/3/avatar?v=1718900000000"},"message_count":{"type":"string","description":"Number of assistant messages.","example":"991"}},"required":["cost_micro","input_tokens","output_tokens","cache_read_tokens","cache_write_tokens","total_tokens","key","label","message_count"]},"CostAnalyticsDto":{"type":"object","properties":{"from":{"type":"string","description":"Effective lower bound (ISO).","example":"2026-05-20T00:00:00.000Z"},"to":{"type":"string","description":"Effective upper bound (ISO).","example":"2026-06-19T00:00:00.000Z"},"bucket":{"enum":["hour","day","month","week"],"type":"string","description":"Bucket granularity used.","example":"day"},"group_by":{"enum":["agent","channel","scope","transport","model","contact","conversation","cron"],"type":"string","description":"Dimension grouped by.","example":"agent"},"totals":{"description":"Totals over the whole window.","allOf":[{"$ref":"#/components/schemas/CostFiguresDto"}]},"series":{"description":"Cost per time bucket (ascending).","type":"array","items":{"$ref":"#/components/schemas/CostSeriesPointDto"}},"breakdown":{"description":"Cost per dimension value (highest cost first).","type":"array","items":{"$ref":"#/components/schemas/CostBreakdownRowDto"}}},"required":["from","to","bucket","group_by","totals","series","breakdown"]},"GetCapabilityDto":{"type":"object","properties":{"id":{"type":"number","description":"Capability id","example":1},"key":{"type":"string","description":"Stable slug — the agent-base/supervisor look at this.","example":"playwright"},"label":{"type":"string","description":"Display name","example":"Playwright + Chromium"},"description":{"type":"string","nullable":true,"description":"Long description"},"icon":{"type":"string","nullable":true,"description":"Lucide icon name hint for the frontend","example":"theater"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"}},"required":["id","key","label","created_at","updated_at"]},"ListCapabilityDto":{"type":"object","properties":{"data":{"description":"Items in the current page","type":"array","items":{"$ref":"#/components/schemas/GetCapabilityDto"}},"total":{"type":"number","description":"Total number of items matching the query","example":5},"page":{"type":"number","description":"Current page (1-indexed)","example":1},"limit":{"type":"number","description":"Page size","example":20}},"required":["data","total","page","limit"]},"InboxAgentBadgeDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":3},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"}},"required":["id","name"]},"InboxAssigneeDto":{"type":"object","properties":{"kind":{"enum":["AGENT","USER"],"type":"string","description":"Discriminator: USER (human operator) or AGENT (Claude agent)","example":"AGENT"},"id":{"type":"number","description":"Assignee id (user.id or agent.id depending on kind)","example":5},"name":{"type":"string","description":"Display name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url for AGENT kind (proxy endpoint), null for USER"}},"required":["kind","id","name"]},"InboxChannelBadgeDto":{"type":"object","properties":{"id":{"type":"number","description":"Channel id","example":2},"transport":{"type":"string","description":"Channel transport","example":"INTERNAL"},"name":{"type":"string","description":"Channel name","example":"Internal operators"}},"required":["id","transport","name"]},"InboxLastMessageDto":{"type":"object","properties":{"id":{"type":"number","description":"Message id","example":42},"role":{"type":"string","description":"Role","example":"ASSISTANT"},"kind":{"type":"string","description":"Message kind","example":"TEXT"},"preview":{"type":"string","nullable":true,"description":"Short text preview (best-effort from content)","example":"Sí, te llamas Maria Test"},"created_at":{"format":"date-time","type":"string","description":"Created at"}},"required":["id","role","kind","created_at"]},"InboxConversationDto":{"type":"object","properties":{"id":{"type":"number","description":"Conversation id","example":7},"status":{"type":"string","description":"Status","example":"OPEN"},"session_id":{"type":"string","description":"Claude session UUID","example":"a1b2…"},"opened_at":{"format":"date-time","type":"string","description":"Opened at"},"last_activity_at":{"format":"date-time","type":"string","description":"Last activity at"},"last_message":{"nullable":true,"description":"Last message preview","type":"object","allOf":[{"$ref":"#/components/schemas/InboxLastMessageDto"}]}},"required":["id","status","session_id","opened_at","last_activity_at"]},"InboxContactDto":{"type":"object","properties":{"id":{"type":"number","description":"Contact id","example":12},"kind":{"type":"string","description":"Contact kind","example":"EXTERNAL"},"name":{"type":"string","description":"Contact display name","example":"Maria"},"agent":{"nullable":true,"description":"Legacy \"owner\" agent of this contact (kept for backwards compat — prefer `assignee`).","type":"object","allOf":[{"$ref":"#/components/schemas/InboxAgentBadgeDto"}]},"assignee":{"nullable":true,"description":"Current Agent Desk assignee (human operator or agent). Null when nobody is currently handling the contact (fresh inbound).","type":"object","allOf":[{"$ref":"#/components/schemas/InboxAssigneeDto"}]},"channels":{"description":"Channels the contact is reachable through","type":"array","items":{"$ref":"#/components/schemas/InboxChannelBadgeDto"}},"conversations":{"description":"Conversations sorted by last_activity_at desc","type":"array","items":{"$ref":"#/components/schemas/InboxConversationDto"}},"last_activity_at":{"format":"date-time","type":"string","description":"Most recent activity across the contact"}},"required":["id","kind","name","channels","conversations","last_activity_at"]},"ListInboxDto":{"type":"object","properties":{"data":{"description":"Contacts grouped, each carrying conversation list","type":"array","items":{"$ref":"#/components/schemas/InboxContactDto"}},"total":{"type":"number","description":"Total contacts matched (not conversations)"}},"required":["data","total"]},"InboxIdentityDto":{"type":"object","properties":{"id":{"type":"number","description":"Identity id","example":9},"channel":{"description":"Channel this identity belongs to","allOf":[{"$ref":"#/components/schemas/InboxChannelBadgeDto"}]},"identifier":{"type":"string","description":"Stable identifier (email, phone, user_id, …)","example":"user:42"},"display_name":{"type":"string","nullable":true,"description":"Display name (optional)"},"first_seen_at":{"format":"date-time","type":"string","description":"First seen at"},"last_seen_at":{"format":"date-time","type":"string","description":"Last seen at"}},"required":["id","channel","identifier","first_seen_at","last_seen_at"]},"GetInboxContactDto":{"type":"object","properties":{"id":{"type":"number","description":"Contact id","example":12},"kind":{"type":"string","description":"Contact kind","example":"EXTERNAL"},"name":{"type":"string","description":"Contact display name","example":"Maria"},"user_id":{"type":"number","nullable":true,"description":"Linked user id (operator contacts only)"},"agent":{"nullable":true,"description":"Legacy \"owner\" agent (kept for backwards compat — prefer `assignee`).","type":"object","allOf":[{"$ref":"#/components/schemas/InboxAgentBadgeDto"}]},"assignee":{"nullable":true,"description":"Current Agent Desk assignee. Null if unassigned.","type":"object","allOf":[{"$ref":"#/components/schemas/InboxAssigneeDto"}]},"identities":{"description":"All identities this contact has (one per channel)","type":"array","items":{"$ref":"#/components/schemas/InboxIdentityDto"}},"conversations":{"description":"All conversations (open + closed) ordered by last_activity_at desc","type":"array","items":{"$ref":"#/components/schemas/InboxConversationDto"}},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"}},"required":["id","kind","name","identities","conversations","created_at","updated_at"]},"InboxAssigneeUserDto":{"type":"object","properties":{"id":{"type":"number","description":"User id","example":2},"name":{"type":"string","description":"Display name","example":"Alice"},"email":{"type":"string","description":"Email","example":"alice@example.com"},"role":{"type":"string","description":"Membership role","example":"OPERATOR"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"}},"required":["id","name","email","role"]},"InboxAssigneeAgentDto":{"type":"object","properties":{"id":{"type":"number","description":"Agent id","example":5},"name":{"type":"string","description":"Agent name","example":"Captain"},"avatar_url":{"type":"string","nullable":true,"description":"Avatar url (proxy endpoint)"}},"required":["id","name"]},"ListInboxAssigneesDto":{"type":"object","properties":{"users":{"description":"Members of the organization eligible to be assigned","type":"array","items":{"$ref":"#/components/schemas/InboxAssigneeUserDto"}},"agents":{"description":"Agents in the organization eligible to be assigned","type":"array","items":{"$ref":"#/components/schemas/InboxAssigneeAgentDto"}}},"required":["users","agents"]},"SetConversationStatusDto":{"type":"object","properties":{"status":{"enum":["open","pending","resolved"],"type":"string","description":"Target status for the conversation. open = reactive / reopen, pending = waiting for action, resolved = closed."}},"required":["status"]},"SetAssigneeDto":{"type":"object","properties":{"user_id":{"type":"number","nullable":true,"minimum":1,"description":"Human operator to assign. Null to clear."},"agent_id":{"type":"number","nullable":true,"minimum":1,"description":"Agent to assign. Null to clear."}}},"McpCatalogFieldDto":{"type":"object","properties":{"key":{"type":"string","description":"Logical name.","example":"token"},"label":{"type":"string","description":"Human label shown above the input.","example":"Personal Access Token"},"secret":{"type":"boolean","description":"Rendered as a password input.","example":true},"placeholder":{"type":"string","nullable":true,"description":"Example text for the input placeholder."},"env_var":{"type":"string","nullable":true,"description":"Env var name this field resolves to when not referenced in command/args/url."}},"required":["key","label","secret"]},"GetMcpCatalogDto":{"type":"object","properties":{"id":{"type":"number","description":"Catalog entry id","example":1},"key":{"type":"string","description":"Stable slug","example":"github"},"name":{"type":"string","description":"Display name","example":"GitHub"},"description":{"type":"string","description":"One-line description","example":"Repos, issues, PRs y Actions."},"category":{"enum":["search","data","dev","design","files","infra","productivity","utility"],"type":"string","description":"Filter-chip grouping, as a key from a closed set — the panel writes it in the reader's language.","example":"dev"},"docs_url":{"type":"string","nullable":true,"description":"Where to get what this entry asks for — the tool's setup guide, or its website. Shown next to the fields; null when the entry has no link.","example":"https://docs.github.com/en/authentication"},"avatar_url":{"type":"string","nullable":true,"description":"Uploaded logo. Null falls back to a generic placeholder."},"transport":{"enum":["STDIO","SSE","HTTP"],"type":"string","example":"STDIO"},"command":{"type":"string","nullable":true,"description":"STDIO only."},"args":{"description":"STDIO only argv — may contain {{field.key}} placeholders.","type":"array","items":{"type":"string"}},"url":{"type":"string","nullable":true,"description":"SSE/HTTP only — may contain a {{field.key}} placeholder."},"fields":{"description":"What the picker asks the operator for.","type":"array","items":{"$ref":"#/components/schemas/McpCatalogFieldDto"}},"sort_order":{"type":"number","description":"Sort order (lower first).","example":10},"active":{"type":"boolean","description":"Offered in the picker.","example":true},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"},"translations":{"type":"object","additionalProperties":true,"description":"Raw translations by field path and locale, e.g. `{ \"name\": { \"EN\": \"Web search\" } }`. Staff only (`?i18n=1`): everyone else reads the strings above, already in their language.","example":{"name":{"EN":"Web search"}}}},"required":["id","key","name","description","category","transport","args","fields","sort_order","active","created_at","updated_at"]},"GetHostDto":{"type":"object","properties":{"id":{"type":"number","description":"Host id","example":1},"organization_id":{"type":"number","description":"Organization id","example":1},"name":{"type":"string","description":"Display name","example":"portatil-ana"},"hostname":{"type":"string","nullable":true,"description":"Hostname reported by the binary"},"machine_id":{"type":"string","nullable":true,"description":"Machine identity reported by the binary (unique per org)"},"os":{"type":"string","nullable":true,"description":"Operating system label"},"host_version":{"type":"string","nullable":true,"description":"kj-host binary version"},"status":{"enum":["UNPAIRED","ONLINE","OFFLINE"],"type":"string","description":"Lifecycle status","example":"UNPAIRED"},"disabled":{"type":"boolean","description":"Whether the host is cut (disabled) — the handshake refuses it","example":false},"active":{"type":"boolean","description":"Whether the «active» switch is on in the binary. When off, an agent can only read data (OBSERVE) and ask the person to switch on; when on, it may use the allowed layers.","example":false},"allowed_layers":{"type":"array","items":{"type":"string","enum":["OBSERVE","FILES","TERMINAL","SCREEN"]},"description":"Access layers the person ticked in the binary, reported by the machine. What any agent linked to this device may use (with the active switch on).","example":["OBSERVE"]},"last_seen_at":{"format":"date-time","type":"string","nullable":true,"description":"Last heartbeat timestamp"},"cpu_percent":{"type":"number","nullable":true,"description":"CPU usage (0..100), last telemetry"},"ram_percent":{"type":"number","nullable":true,"description":"RAM usage (0..100), last telemetry"},"disk_percent":{"type":"number","nullable":true,"description":"Disk usage (0..100), last telemetry"},"uptime_seconds":{"type":"number","nullable":true,"description":"Uptime in seconds, last telemetry"},"provisioning_expires_at":{"format":"date-time","type":"string","nullable":true,"description":"Provisioning token expiry"},"provisioning_token":{"type":"string","description":"Provisioning token (only at create/regenerate time)"},"created_at":{"format":"date-time","type":"string","description":"Created at"},"updated_at":{"format":"date-time","type":"string","description":"Updated at"}},"required":["id","organization_id","name","status","disabled","active","allowed_layers","created_at","updated_at"]},"ListHostDto":{"type":"object","properties":{"data":{"description":"Items in the current page","type":"array","items":{"$ref":"#/components/schemas/GetHostDto"}},"total":{"type":"number","description":"Total number of items matching the query","example":42},"page":{"type":"number","description":"Current page (1-indexed)","example":1},"limit":{"type":"number","description":"Page size","example":20}},"required":["data","total","page","limit"]},"CreateHostDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Display name (unique within the org)","example":"portatil-ana"},"hostname":{"type":"string","maxLength":120,"description":"Free-form hostname hint (the binary refreshes it on connect)","example":"ANA-LAPTOP"}},"required":["name"]}}}}