> ## Documentation Index
> Fetch the complete documentation index at: https://apidocs.document360.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Run an AI search query
> Sends a natural language query to the AI assistive search engine and returns a generated answer based on
the project's documentation content. Both `WorkspaceId` and `Query` are required in the
request body; a `422` is returned if either is missing or empty. Use `POST /v3/projects/{projectId}/workspaces/ai/feedback`
to submit user feedback on the generated response: send the `query_id` from this response as the
feedback request's `query_id`.
Response.`source_article_ids` lists the ids of the knowledge base entries used to build the
answer (an article id, or a category id for a page category). For an attachment, the id of the article
(or page category) that contains it is listed. External sources have no id and are not listed.
`sources` gives the full details of every source (article, page category, external source or
attachment, where each attachment is a separate entry): title, slug, category, workspace, language and
link, so a client can render a citation list with no extra requests. For a private or mixed project, an
attachment URL contains a time-limited read token that is scoped to the project's storage container, not
to the one file. `remaining_credits` and `limit_exceeded` report the project's AI credit state.
When no answer is generated (no content matches the query, or the model did not use the retrieved
content), the answer is `No answer` and `source_article_ids` and `sources` are empty.
`remaining_credits` and `limit_exceeded` still report the credit state, because no credit is
used. They are `null` only when the AI answer service fails and the credit state is not known.
Options. The request body accepts the same options as the Customer API V2 `ask-eddy` endpoint:
Content scope. The answer is generated only from content the calling principal may read. The
requested workspace must be within the caller's content access, and the caller must have access to the
requested `lang_code` in that workspace (otherwise `404`). For protected or mixed projects the
caller's category and article restrictions are applied to the source documents as well, so an answer is
never synthesised from denied content. For projects whose protection level is fully public, all
published content in the workspace is eligible — it is readable by anyone on the knowledge base site
regardless of API permissions.
## OpenAPI
````json POST /v3/projects/{project_id}/workspaces/ai/query
{
"openapi": "3.0.1",
"info": {
"title": "Document360 Customer API",
"description": "Document360 RESTful APIs let you integrate your documentation with your software — onboard readers, manage articles, automate publishing, and more.\n\nFull reference: [API Documentation](https://apidocs.document360.io/docs).\n\n## Authentication\nV3 authenticates with an **API key** — not the `api_token` used by V1/V2. Create one in the Document360 portal under **Settings → Knowledge base portal → API keys**, then click **Create API key**. (Projects that still have the older screen show two tabs; choose **Enhanced keys (v3)**, or pick **API v3** from the Create menu.)\n\nSend it in the `X-API-Key` header:\n\n```\nX-API-Key: d360_sk_...\n```\n\nThe plaintext key is shown **once**, at creation — only its hash is stored, so a lost key must be replaced rather than recovered. Each key carries a fixed portal role, content role and content-access scope, supports an optional expiry, and can be disabled or deleted at any time from the same screen. Treat it as an opaque string: it is a pre-shared secret, not an OAuth 2.0 access token, and must not be parsed.\n\nFor flows that act on behalf of a specific person, V3 also accepts an OAuth 2.0 bearer token carrying the `customerApi` scope.\n\nAPI access is part of your subscription plan. If your plan does not include it, every endpoint returns `403` with the error code `FEATURE_NOT_IN_LICENSE` — including for keys created while an earlier plan was active. Contact your Customer Success Manager or `support@document360.com` to enable it.\n\n> **Note on terminology:** V1/V2 call these *API tokens* and manage them under **Settings → Knowledge base portal → API tokens**. V3 keys are a separate credential with their own screen, roles and scope — a V1/V2 token will not authenticate a V3 request.\n\n## Rate Limits\nAll endpoints are rate-limited per API key per project, with separate limits for reads (`GET`/`HEAD`) and writes (`POST`/`PUT`/`PATCH`/`DELETE`). Default limits vary by plan. When rate-limited, responses include `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers. Use exponential backoff with jitter for optimal retry behavior.",
"termsOfService": "https://document360.com/terms",
"contact": {
"name": "Document360 Support",
"url": "https://document360.io/contact-us/",
"email": "support@document360.com"
},
"license": {
"name": "Document360 API Terms of Use",
"url": "https://document360.com/terms"
},
"version": "3.0.0"
},
"servers": [
{
"url": "https://apihub.document360.io",
"description": "Document 360 API Hub"
},
{
"url": "https://apihub.us.document360.io",
"description": "Document360 API Hub - US data center"
},
{
"url": "https://apihub.{private_hosting}.document360.io",
"description": "Private hosting - Please provide the subdomain name.",
"variables": {
"private_hosting": {
"default": "domain",
"description": "Sub domain for private hosting"
}
}
}
],
"security": [
{
"ApiKey": []
},
{
"Bearer": [
"customerApi"
]
}
],
"tags": [
{
"name": "Projects",
"description": "List and manage knowledge base projects. Export and import project documentation, and manage project-level site customization such as custom CSS and JavaScript."
},
{
"name": "Projects > Import & export",
"description": "Start a project export or import and poll the resulting background operation for completion."
},
{
"name": "Workspaces",
"description": "Manage workspaces and access workspace-scoped categories and articles."
},
{
"name": "Workspaces > AI",
"description": "Query the workspace with Eddy AI, submit feedback on AI answers, and read that feedback with its conversation."
},
{
"name": "Articles",
"description": "Create, read, update, and delete knowledge base articles and their settings, including bulk operations."
},
{
"name": "Articles > Publishing & workflow",
"description": "Publish and unpublish articles (single and bulk) and update the article workflow status."
},
{
"name": "Articles > Versions",
"description": "List, fork, and delete article versions."
},
{
"name": "Articles > Attachments",
"description": "Manage the files attached to an article — list, upload, and delete article attachments."
},
{
"name": "Articles > Content drafts",
"description": "(Internal) Stage AI-generated article content with an Accept/Reject review lifecycle — used by Eddy Copilot to preview content before committing to the live article body."
},
{
"name": "Articles > Labels",
"description": "Read and set the labels associated with an article."
},
{
"name": "Articles > Comments",
"description": "Read and create the comment threads authors and reviewers leave on an article's content, and reply to them. Each comment id matches the `data-comment-id` attribute of the corresponding marker in the raw article content, so adding a text-anchored comment takes two calls: update the content with the marker, then create the thread with the same id."
},
{
"name": "Categories",
"description": "Manage the category hierarchy that organizes articles. Create, update, and delete categories and their settings, including bulk operations."
},
{
"name": "Categories > Page category",
"description": "Read and update the content body of page-type categories, including bulk content updates."
},
{
"name": "Categories > Publishing & workflow",
"description": "Publish and unpublish categories (single and bulk) and update the category workflow status."
},
{
"name": "Categories > Versions",
"description": "List, fork, and delete category versions."
},
{
"name": "Categories > Labels",
"description": "Read and set the labels associated with a category."
},
{
"name": "Categories > Comments",
"description": "Read and create the comment threads authors and reviewers leave on a page category's content, and reply to them. Only page-type categories carry content, so other category types return `404`. Adding a text-anchored comment takes two calls: update the content with the marker, then create the thread with the same id."
},
{
"name": "ArticleTemplates",
"description": "Manage reusable article templates — per-language article skeletons that authors and AI tools (such as Eddy Copilot) can apply when starting a new article.",
"x-displayName": "Article templates"
},
{
"name": "Content reuse > Glossaries",
"description": "Manage glossary entries — terminology definitions referenced inside articles via merge codes (`{{glossary.name}}`) and rendered as tooltips on the public KB."
},
{
"name": "Content reuse > Snippets",
"description": "Manage reusable snippets — markdown or WYSIWYG content fragments referenced across articles via merge codes (`{{snippet.name}}`)."
},
{
"name": "Content reuse > Variables",
"description": "Manage reusable variables — short text values referenced across articles via merge codes (`{{variable.name}}`)."
},
{
"name": "AiWriterStyleGuides",
"description": "Retrieve AI writer style guides configured for the project — voice / tone instructions Eddy Copilot follows when generating article content. Used to let users pick a style before kicking off generation.",
"x-displayName": "AI writer style guides"
},
{
"name": "RedirectRules",
"description": "Manage article-redirection rules — 301/302 redirects from old article URLs to new locations after renames or restructures.",
"x-displayName": "Redirect rules"
},
{
"name": "Tags",
"description": "Manage tags — labels used to classify articles, categories, and files for filtering and discovery."
},
{
"name": "Labels",
"description": "Manage labels shown on the article list and category tree. (Associating labels with a specific article or category lives under Articles and Categories.)"
},
{
"name": "MirroredArticles",
"description": "List, read and create mirrored articles — read-only copies of a source article placed in other categories or workspaces of the project, including bulk mirroring."
},
{
"name": "CustomFields",
"description": "Retrieve the custom field definitions configured for the project. Custom field values are read and written through the article and category settings endpoints.",
"x-displayName": "Custom fields"
},
{
"name": "ApiReferences",
"description": "Import, resync, and publish OpenAPI/Swagger specifications for API reference documentation.",
"x-displayName": "API references"
},
{
"name": "ApiReferences > Logs",
"description": "Monitor API reference import logs and inspect individual log entries."
},
{
"name": "Drive",
"description": "Search Drive and retrieve files associated with an article, and track Drive background tasks."
},
{
"name": "Drive > Folders",
"description": "Create, read, update, and delete Drive folders."
},
{
"name": "Drive > Files",
"description": "Upload, copy, move, delete, and tag Drive files."
},
{
"name": "Drive > Image drafts",
"description": "(Internal) Stage uploaded or AI-generated images (committed to Drive and associated with a staged article draft) — used by Eddy Copilot."
},
{
"name": "Readers",
"description": "Manage reader accounts, invitations, and access scopes for private documentation."
},
{
"name": "Readers > Groups",
"description": "Create, read, update, and delete reader groups."
},
{
"name": "Users",
"description": "Manage users, their portal and content roles, and consolidated (effective) permissions within a project."
},
{
"name": "Users > Groups",
"description": "Manage user groups, their portal role, and consolidated (effective) group permissions."
},
{
"name": "Roles",
"description": "Create, read, update, and delete portal and content roles, list the users assigned to a role, and retrieve the permission dependency matrix."
},
{
"name": "ContentAccess",
"description": "Manage per-node content-access permissions — grant, allow, deny, and inheritance overrides for users and groups against specific versions, languages, categories, or articles, plus version/language site protection.",
"x-displayName": "Content access"
},
{
"name": "ContentAccess > Eligibility",
"description": "List the readers and groups eligible to be granted content access."
},
{
"name": "Languages",
"description": "Retrieve configured languages for a workspace."
},
{
"name": "Translations",
"description": "Query translation status of articles across languages."
},
{
"name": "Operations",
"description": "Track asynchronous operations — long-running tasks (bulk updates, merges, exports) accepted with `202 Accepted` and an `Operation-Location` header. Poll until the operation reaches a terminal status, honouring the `Retry-After` header."
},
{
"name": "AgentAssist",
"description": "Back end for the Document360 Zendesk app's per-agent mode: workspace, category, article, search and Eddy AI reads executed as the signed-in support agent, plus article and category creation attributed to them.",
"x-displayName": "Agent assist (Zendesk)"
},
{
"name": "ZendeskAppAuth",
"description": "(Internal) Per-agent Document360 sign-in for the Zendesk app: begin a sign-in, receive the Identity callback, claim the agent's session handle, and check or end that session.",
"x-displayName": "Zendesk app sign-in"
},
{
"name": "ZendeskAppAttestation",
"description": "(Internal) The Zendesk app's signed background page: verifies the app token Zendesk signs for the agent at the keyboard and hands the app a short-lived agent pass that lets a sign-in complete silently.",
"x-displayName": "Zendesk app attestation"
},
{
"name": "ZendeskAppConnect",
"description": "(Internal) Completes connecting a project's Zendesk account for silent agent sign-in: the OAuth callback Zendesk redirects the approving admin to.",
"x-displayName": "Zendesk account connection"
},
{
"name": "Analytics > Articles",
"description": "View article performance metrics including views, top articles, reader locations, and category breakdowns."
},
{
"name": "Analytics > Search",
"description": "View search usage metrics including top keywords, no-result queries, and bounced searches."
},
{
"name": "Analytics > AI search",
"description": "View AI-powered search metrics including usage trends, most-referenced articles, and trending topics."
},
{
"name": "FeedbackManagement",
"description": "Manage reader feedback on articles and page categories — list it, read a record, page through its team discussions, and update its status (including closing it) and assignee to sync it with external issue trackers.",
"x-displayName": "Feedback management"
},
{
"name": "Analytics > Feedback",
"description": "View reader feedback trends across articles, including top-performing articles and feedback keywords."
}
],
"externalDocs": {
"description": "Document360 API Documentation",
"url": "https://apidocs.document360.io/docs"
},
"x-tagGroups": [
{
"name": "Workspace",
"tags": [
"Projects",
"Projects > Import & export",
"Workspaces",
"Workspaces > AI"
]
},
{
"name": "Content",
"tags": [
"Articles",
"Articles > Publishing & workflow",
"Articles > Versions",
"Articles > Attachments",
"Articles > Content drafts",
"Articles > Labels",
"Categories",
"Categories > Page category",
"Categories > Publishing & workflow",
"Categories > Versions",
"Categories > Labels",
"ArticleTemplates",
"AiWriterStyleGuides",
"RedirectRules",
"Tags",
"Labels",
"ApiReferences",
"ApiReferences > Logs",
"FeedbackManagement"
]
},
{
"name": "Content reuse",
"tags": [
"Content reuse > Glossaries",
"Content reuse > Snippets",
"Content reuse > Variables"
]
},
{
"name": "Media",
"tags": [
"Drive",
"Drive > Folders",
"Drive > Files",
"Drive > Image drafts"
]
},
{
"name": "Access",
"tags": [
"Readers",
"Readers > Groups",
"Users",
"Users > Groups",
"Roles",
"ContentAccess",
"ContentAccess > Eligibility"
]
},
{
"name": "Localization",
"tags": [
"Languages",
"Translations"
]
},
{
"name": "Operations",
"tags": [
"Operations"
]
},
{
"name": "Integrations",
"tags": [
"AgentAssist",
"ZendeskAppAuth",
"ZendeskAppAttestation",
"ZendeskAppConnect"
]
},
{
"name": "Analytics",
"tags": [
"Analytics > Articles",
"Analytics > Search",
"Analytics > AI search",
"Analytics > Feedback"
]
}
],
"paths": {
"/v3/projects/{project_id}/workspaces/ai/query": {
"post": {
"tags": [
"Workspaces > AI"
],
"summary": "Run an AI search query.",
"description": "Sends a natural language query to the AI assistive search engine and returns a generated answer based on\r\nthe project's documentation content. Both `WorkspaceId` and `Query` are required in the\r\nrequest body; a `422` is returned if either is missing or empty. Use `POST /v3/projects/{projectId}/workspaces/ai/feedback`\r\nto submit user feedback on the generated response: send the `query_id` from this response as the\r\nfeedback request's `query_id`.\r\n\nResponse.`source_article_ids` lists the ids of the knowledge base entries used to build the\r\nanswer (an article id, or a category id for a page category). For an attachment, the id of the article\r\n(or page category) that contains it is listed. External sources have no id and are not listed.\r\n`sources` gives the full details of every source (article, page category, external source or\r\nattachment, where each attachment is a separate entry): title, slug, category, workspace, language and\r\nlink, so a client can render a citation list with no extra requests. For a private or mixed project, an\r\nattachment URL contains a time-limited read token that is scoped to the project's storage container, not\r\nto the one file. `remaining_credits` and `limit_exceeded` report the project's AI credit state.\r\nWhen no answer is generated (no content matches the query, or the model did not use the retrieved\r\ncontent), the answer is `No answer` and `source_article_ids` and `sources` are empty.\r\n`remaining_credits` and `limit_exceeded` still report the credit state, because no credit is\r\nused. They are `null` only when the AI answer service fails and the credit state is not known.\r\n\nOptions. The request body accepts the same options as the Customer API V2 `ask-eddy` endpoint:\r\n
\nContent scope. The answer is generated only from content the calling principal may read. The\r\nrequested workspace must be within the caller's content access, and the caller must have access to the\r\nrequested `lang_code` in that workspace (otherwise `404`). For protected or mixed projects the\r\ncaller's category and article restrictions are applied to the source documents as well, so an answer is\r\nnever synthesised from denied content. For projects whose protection level is fully public, all\r\npublished content in the workspace is eligible — it is readable by anyone on the knowledge base site\r\nregardless of API permissions.\r\n",
"operationId": "postAiQuery",
"parameters": [
{
"$ref": "#/components/parameters/ProjectId"
}
],
"requestBody": {
"description": "The AI query request.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AiQueryRequest"
},
"example": "
Your Zendesk account is connected to Document360. You can close this window.
", "examples": { "Ask the AI assistant": { "summary": "Sends a natural-language question to the AI engine and returns a generated answer based on the workspace's English documentation. lang_code is omitted, so en is used, and the project's AI search settings give the tone and length.", "value": { "query": "How do I configure single sign-on for my customers?", "workspace_id": "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a", "lang_code": null, "enable_citation": false, "response_tone": null, "response_length": null } }, "Ask in a specific language": { "summary": "Queries the workspace's Portuguese (Brazil) content. Use lang_code when the API key has access to a language other than English, for example a key that is scoped to pt-br categories.", "value": { "query": "Como configuro o login único para os meus clientes?", "workspace_id": "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a", "lang_code": "pt-br", "enable_citation": false, "response_tone": null, "response_length": null } }, "Set citation, tone and length": { "summary": "Asks for a short, professional answer with inline citations to the source content. These options override the project's AI search settings for this request only.", "value": { "query": "How do I configure single sign-on for my customers?", "workspace_id": "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a", "lang_code": "en", "enable_citation": true, "response_tone": "professional", "response_length": "shortAndConcise" } } } } } }, "responses": { "200": { "description": "AI response retrieved successfully.", "headers": { "X-RateLimit-Limit": { "description": "The maximum number of requests allowed in the current time window for this request's bucket. Read requests (GET/HEAD) and write requests (POST/PUT/PATCH/DELETE) have independent limits, applied per caller (API key or user) per project.", "schema": { "type": "integer", "format": "int32" } }, "X-RateLimit-Remaining": { "description": "The number of requests remaining in the current time window. When this reaches 0, subsequent requests receive a 429 response.", "schema": { "type": "integer", "format": "int32" } } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AiQueryResponseApiResponse" }, "examples": { "AI answer generated": { "summary": "Returns the AI-generated answer synthesised from knowledge base articles, plus the source article IDs and the full source details used to construct it, the query ID to send with feedback, and the AI credit state.", "value": { "data": { "answer": "To configure SSO authentication, navigate to Settings > SSO and choose your identity provider. SAML, OIDC, and JWT are supported. Complete the provider's metadata fields and run the test connection before enabling SSO for end users.", "query_id": "6f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f", "source_article_ids": [ "9a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d", "c5d6e7f8-9a0b-1c2d-3e4f-5a6b7c8d9e0f" ], "sources": [ { "source_type": "article", "citation_id": null, "article_id": "9a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d", "article_title": "Configure SSO", "article_slug": "configure-sso", "category_id": "e1f2a3b4-c5d6-e7f8-a9b0-c1d2e3f4a5b6", "category_title": "Security", "category_slug": "security", "workspace_name": "v1", "workspace_slug": "v1", "language_code": "en", "external_source_id": null, "external_source_name": null, "external_source_link": null, "attachment_title": null, "attachment_url": null }, { "source_type": "pageCategory", "citation_id": null, "article_id": null, "article_title": null, "article_slug": null, "category_id": "c5d6e7f8-9a0b-1c2d-3e4f-5a6b7c8d9e0f", "category_title": "Identity providers", "category_slug": "identity-providers", "workspace_name": "v1", "workspace_slug": "v1", "language_code": "en", "external_source_id": null, "external_source_name": null, "external_source_link": null, "attachment_title": null, "attachment_url": null }, { "source_type": "externalSource", "citation_id": null, "article_id": null, "article_title": null, "article_slug": null, "category_id": null, "category_title": null, "category_slug": null, "workspace_name": null, "workspace_slug": null, "language_code": "en", "external_source_id": "7b8c9d0e-1f2a-3b4c-5d6e-7f8a9b0c1d2e", "external_source_name": "Engineering wiki", "external_source_link": "https://wiki.example.com/sso-setup", "attachment_title": null, "attachment_url": null } ], "remaining_credits": 4820, "limit_exceeded": false }, "success": true, "request_id": "req_abc123def456", "errors": null, "warnings": null } } } } } }, "401": { "description": "Authentication token is missing or invalid.", "headers": { "WWW-Authenticate": { "description": "Indicates the authentication scheme required. Returns `Bearer` with optional `error` and `error_description` parameters per RFC 6750.", "schema": { "type": "string" } } }, "content": { "application/problem+json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/V3ProblemDetails" }, { "type": "object", "properties": { "type": { "enum": [ "https://apidocs.document360.io/apidocs/errors/unauthorized" ], "type": "string", "description": "RFC 7807 error type URI. Always `https://apidocs.document360.io/apidocs/errors/unauthorized` for 401 responses." }, "status": { "enum": [ 401 ], "type": "integer", "description": "HTTP status code. Always `401` for this response.", "format": "int32" } } } ] }, "examples": { "Missing or invalid token": { "summary": "Authentication token is missing or invalid.", "value": { "type": "https://apidocs.document360.io/apidocs/errors/unauthorized", "title": "Unauthorized.", "status": 401, "detail": "The authentication token is missing or has expired.", "instance": null, "trace_id": "req_abc123def456", "errors": [ { "code": "UNAUTHORIZED", "message": "Bearer token is missing or invalid.", "field": null, "details": null } ], "warnings": null } } } } } }, "403": { "description": "Token lacks the required scope or content permission.", "content": { "application/problem+json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/V3ProblemDetails" }, { "type": "object", "properties": { "type": { "enum": [ "https://apidocs.document360.io/apidocs/errors/forbidden" ], "type": "string", "description": "RFC 7807 error type URI. Always `https://apidocs.document360.io/apidocs/errors/forbidden` for 403 responses." }, "status": { "enum": [ 403 ], "type": "integer", "description": "HTTP status code. Always `403` for this response.", "format": "int32" } } } ] }, "examples": { "Insufficient permissions": { "summary": "Insufficient permissions for this resource.", "value": { "type": "https://apidocs.document360.io/apidocs/errors/forbidden", "title": "Forbidden.", "status": 403, "detail": "You do not have permission to perform this action.", "instance": null, "trace_id": "req_abc123def456", "errors": [ { "code": "FORBIDDEN", "message": "Insufficient permissions for this project.", "field": null, "details": null } ], "warnings": null } } } } } }, "404": { "description": "The workspace does not exist, or the caller's content access does not include it in the requested language.", "content": { "application/problem+json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/V3ProblemDetails" }, { "type": "object", "properties": { "type": { "enum": [ "https://apidocs.document360.io/apidocs/errors/resource-not-found" ], "type": "string", "description": "RFC 7807 error type URI. Always `https://apidocs.document360.io/apidocs/errors/resource-not-found` for 404 responses." }, "status": { "enum": [ 404 ], "type": "integer", "description": "HTTP status code. Always `404` for this response.", "format": "int32" } } } ] }, "examples": { "Resource not found": { "summary": "The requested resource does not exist.", "value": { "type": "https://apidocs.document360.io/apidocs/errors/resource-not-found", "title": "Resource not found.", "status": 404, "detail": "The requested resource was not found.", "instance": null, "trace_id": "req_abc123def456", "errors": [ { "code": "RESOURCE_NOT_FOUND", "message": "Resource not found.", "field": null, "details": null } ], "warnings": null } } } } } }, "422": { "description": "Validation failed: `query` or `workspace_id` is empty, `lang_code` is not a valid language code or does not support AI search, or `response_tone` / `response_length` is not a known value.", "content": { "application/problem+json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/V3ProblemDetails" }, { "type": "object", "properties": { "type": { "enum": [ "https://apidocs.document360.io/apidocs/errors/validation-error" ], "type": "string", "description": "RFC 7807 error type URI. Always `https://apidocs.document360.io/apidocs/errors/validation-error` for 422 responses." }, "status": { "enum": [ 422 ], "type": "integer", "description": "HTTP status code. Always `422` for this response.", "format": "int32" } } } ] }, "examples": { "Validation failed": { "summary": "One or more request fields failed validation.", "value": { "type": "https://apidocs.document360.io/apidocs/errors/validation-error", "title": "Validation Error", "status": 422, "detail": "One or more fields failed validation.", "instance": null, "trace_id": "req_abc123def456", "errors": [ { "code": "VALIDATION_ERROR", "message": "The field is required.", "field": "name", "details": null } ], "warnings": null } } } } } }, "400": { "description": "The request body is malformed or contains invalid JSON.", "content": { "application/problem+json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/V3ProblemDetails" }, { "type": "object", "properties": { "type": { "enum": [ "https://apidocs.document360.io/apidocs/errors/bad-request" ], "type": "string", "description": "RFC 7807 error type URI. Always `https://apidocs.document360.io/apidocs/errors/bad-request` for 400 responses." }, "status": { "enum": [ 400 ], "type": "integer", "description": "HTTP status code. Always `400` for this response.", "format": "int32" } } } ] }, "examples": { "Malformed request body": { "summary": "The request body could not be parsed.", "value": { "type": "https://apidocs.document360.io/apidocs/errors/bad-request", "title": "Bad Request.", "status": 400, "detail": "The request body is malformed or contains invalid JSON.", "instance": null, "trace_id": "req_abc123def456", "errors": [ { "code": "BAD_REQUEST", "message": "Could not parse the request body. Ensure it is valid JSON.", "field": null, "details": null } ], "warnings": null } } } } } }, "429": { "description": "Rate limit exceeded. Retry after the duration specified in the Retry-After header.", "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying the request. Use exponential backoff with jitter for optimal retry behavior.", "schema": { "type": "integer", "format": "int32" } }, "X-RateLimit-Limit": { "description": "The maximum number of requests allowed in the current time window for this request's bucket. Read requests (GET/HEAD) and write requests (POST/PUT/PATCH/DELETE) have independent limits, applied per caller (API key or user) per project. Read limits are typically higher than write limits.", "schema": { "type": "integer", "format": "int32" } }, "X-RateLimit-Remaining": { "description": "The number of requests remaining in the current time window. When this reaches 0, subsequent requests will receive a 429 response.", "schema": { "type": "integer", "format": "int32" } }, "X-RateLimit-Reset": { "description": "Number of seconds until the current rate limit window resets.", "schema": { "type": "integer", "format": "int64" } } }, "content": { "application/problem+json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/V3ProblemDetails" }, { "type": "object", "properties": { "type": { "enum": [ "https://apidocs.document360.io/apidocs/errors/too-many-requests" ], "type": "string", "description": "RFC 7807 error type URI. Always `https://apidocs.document360.io/apidocs/errors/too-many-requests` for 429 responses." }, "status": { "enum": [ 429 ], "type": "integer", "description": "HTTP status code. Always `429` for this response.", "format": "int32" } } } ] }, "examples": { "Rate limit exceeded": { "summary": "Rate limit exceeded.", "value": { "type": "https://apidocs.document360.io/apidocs/errors/too-many-requests", "title": "Too Many Requests.", "status": 429, "detail": "Rate limit exceeded. Retry after the duration specified in the Retry-After header.", "instance": null, "trace_id": "req_abc123def456", "errors": [ { "code": "TOO_MANY_REQUESTS", "message": "Rate limit exceeded. Retry after the duration specified in the Retry-After header.", "field": null, "details": null } ], "warnings": null } } } } } }, "500": { "description": "An unexpected server error occurred.", "content": { "application/problem+json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/V3ProblemDetails" }, { "type": "object", "properties": { "type": { "enum": [ "https://apidocs.document360.io/apidocs/errors/internal-server-error" ], "type": "string", "description": "RFC 7807 error type URI. Always `https://apidocs.document360.io/apidocs/errors/internal-server-error` for 500 responses." }, "status": { "enum": [ 500 ], "type": "integer", "description": "HTTP status code. Always `500` for this response.", "format": "int32" } } } ] }, "examples": { "Unexpected server error": { "summary": "Unexpected server error.", "value": { "type": "https://apidocs.document360.io/apidocs/errors/internal-server-error", "title": "Internal Server Error.", "status": 500, "detail": "An unexpected error occurred. Please try again or contact support.", "instance": null, "trace_id": "req_abc123def456", "errors": [ { "code": "INTERNAL_SERVER_ERROR", "message": "An unexpected error occurred.", "field": null, "details": null } ], "warnings": null } } } } } } }, "security": [ { "ApiKey": [] }, { "Bearer": [ "customerApi" ] } ] } } }, "components": { "parameters": { "ProjectId": { "name": "project_id", "in": "path", "description": "The unique identifier of the project. Retrieve project IDs from `GET /v3/projects`.", "required": true, "schema": { "type": "string", "format": "uuid", "example": "9a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d" } } }, "schemas": { "AiQueryRequest": { "required": [ "query", "workspace_id" ], "type": "object", "properties": { "query": { "minLength": 1, "type": "string", "description": "The natural language question to ask the AI assistant.", "example": "How do I configure SSO authentication?" }, "workspace_id": { "minLength": 1, "type": "string", "description": "Unique identifier of the workspace to search within.", "example": "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a" }, "lang_code": { "maxLength": 16, "minLength": 0, "pattern": "^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$", "type": "string", "description": "Language code of the workspace content to query (for example `en`, `fr` or `pt-br`).\r\nThe caller's language restrictions are checked against this language. The language must support AI\r\nsearch; otherwise the request fails with `422`. When omitted, `en` is used. The value must be a\r\nlanguage code of at most 16 characters: a 2- or 3-letter primary code, optionally followed by up to two\r\nsubtags (letters or digits) separated by hyphens. Other values fail with `422`.", "nullable": true, "example": "en" }, "enable_citation": { "type": "boolean", "description": "When `true`, the answer includes inline citations that refer to the source content. When\r\n`false` or omitted, the answer has no inline citations. Inline citations are never added when\r\ncitations are turned off in the project's AI search settings. The `sources` list in the response\r\nis returned in all cases.", "example": true }, "response_tone": { "allOf": [ { "$ref": "#/components/schemas/AiResponseTone" } ], "description": "Tone of the generated answer. When omitted, the project's AI search setting is used.", "nullable": true, "example": "professional" }, "response_length": { "allOf": [ { "$ref": "#/components/schemas/AiResponseLength" } ], "description": "Length of the generated answer. When omitted, the project's AI search setting is used.", "nullable": true, "example": "shortAndConcise" } }, "additionalProperties": false, "description": "Request to submit a natural language query to the AI-powered knowledge base search." }, "AiQueryResponseApiResponse": { "required": [ "data", "request_id", "success" ], "type": "object", "properties": { "data": { "allOf": [ { "$ref": "#/components/schemas/AiQueryResponse" } ], "description": "Response data payload." }, "success": { "type": "boolean", "description": "Whether the API request was successful.", "readOnly": true }, "request_id": { "minLength": 1, "type": "string", "description": "Unique identifier for request tracing and correlation.", "readOnly": true }, "errors": { "type": "array", "items": { "$ref": "#/components/schemas/ApiError" }, "description": "List of errors if the request failed.", "nullable": true }, "warnings": { "type": "array", "items": { "$ref": "#/components/schemas/ApiWarning" }, "description": "List of non-fatal warnings from the request.", "nullable": true } }, "additionalProperties": false, "description": "Generic API response wrapper containing typed data." }, "V3ProblemDetails": { "required": [ "status", "title", "type" ], "type": "object", "properties": { "type": { "minLength": 1, "enum": [ "https://apidocs.document360.io/apidocs/errors/bad-request", "https://apidocs.document360.io/apidocs/errors/unauthorized", "https://apidocs.document360.io/apidocs/errors/forbidden", "https://apidocs.document360.io/apidocs/errors/resource-not-found", "https://apidocs.document360.io/apidocs/errors/conflict", "https://apidocs.document360.io/apidocs/errors/validation-error", "https://apidocs.document360.io/apidocs/errors/too-many-requests", "https://apidocs.document360.io/apidocs/errors/internal-server-error" ], "type": "string", "description": "URI reference identifying the error type (links to documentation)." }, "title": { "minLength": 1, "type": "string", "description": "Short human-readable summary of the error type." }, "status": { "enum": [ 400, 401, 403, 404, 409, 422, 429, 500 ], "type": "integer", "description": "HTTP status code.", "format": "int32" }, "detail": { "type": "string", "description": "Human-readable explanation specific to this occurrence.", "nullable": true }, "instance": { "type": "string", "description": "URI of the request that generated the error.", "nullable": true }, "trace_id": { "type": "string", "description": "Request trace identifier for correlation.", "nullable": true }, "errors": { "type": "array", "items": { "$ref": "#/components/schemas/ApiError" }, "description": "Structured list of specific errors (extension field).", "nullable": true }, "warnings": { "type": "array", "items": { "$ref": "#/components/schemas/ApiWarning" }, "description": "Non-fatal warnings (extension field).", "nullable": true } }, "additionalProperties": false, "description": "RFC 7807 Problem Details response for V3 API errors.\r\nContent-Type: application/problem+json" }, "AiResponseTone": { "enum": [ "default", "professional", "friendly", "casual", "straightforward", "confident" ], "type": "string", "description": "Tone of an AI-generated answer.", "x-enumNames": [ "Default", "Professional", "Friendly", "Casual", "Straightforward", "Confident" ], "x-enum-varnames": [ "Default", "Professional", "Friendly", "Casual", "Straightforward", "Confident" ], "x-ms-enum": { "name": "AiResponseTone", "modelAsString": true } }, "AiResponseLength": { "enum": [ "default", "longAndDetailed", "shortAndConcise" ], "type": "string", "description": "Length of an AI-generated answer.", "x-enumNames": [ "Default", "LongAndDetailed", "ShortAndConcise" ], "x-enum-varnames": [ "Default", "LongAndDetailed", "ShortAndConcise" ], "x-ms-enum": { "name": "AiResponseLength", "modelAsString": true } }, "AiQueryResponse": { "type": "object", "properties": { "answer": { "type": "string", "description": "The AI-generated answer to the user's query, synthesized from knowledge base articles.", "nullable": true }, "query_id": { "type": "string", "description": "Identifier of this AI query. Send it as `query_id` to `POST /v3/projects/{projectId}/workspaces/ai/feedback`\r\nto record feedback on the answer. `null` when no analytics record was created for the query.", "nullable": true, "example": "6f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f" }, "source_article_ids": { "type": "array", "items": { "type": "string" }, "description": "List of article IDs that were used as sources to generate the answer. For a page-category source,\r\nthe category ID is given. For an attachment, the ID of the article (or page category) that contains\r\nit is given, so the attachment itself is not a separate entry; use `sources` to get the\r\nattachment details. External sources have no ID and are not included. Each ID is given one time.\r\nEmpty (never `null`) when no knowledge base entry was used, and always empty when the answer is\r\n`No answer`.", "nullable": true }, "sources": { "type": "array", "items": { "$ref": "#/components/schemas/AiQuerySource" }, "description": "Full details of every source used to generate the answer, in first-seen order. Use this list to render\r\na citation list without extra requests. Unlike `source_article_ids`, it also includes external\r\nsources, and it gives each attachment as a separate entry (with `source_type``attachment`), where `source_article_ids` gives only the ID of its parent. Empty (never `null`) when no\r\nsource was used, and always empty when the answer is `No answer`.", "nullable": true }, "remaining_credits": { "type": "integer", "description": "AI credits that remain for the project after this query. Also set when no answer was generated (no\r\ncredit is used then). `null` only when the AI answer service failed and the balance is not known.\r\nA `null` value does not mean that no credits remain; use `limit_exceeded` to detect an\r\nexhausted limit.", "format": "int32", "nullable": true, "example": 4820 }, "limit_exceeded": { "type": "boolean", "description": "`true` when the project's AI credit limit is exhausted and no answer could be generated.\r\n `false` when the limit is not exhausted. `null` only when the AI answer service failed and\r\n the credit state is not known.", "nullable": true, "example": false } }, "additionalProperties": false, "description": "Response from the AI-powered knowledge base search containing the generated answer." }, "ApiError": { "required": [ "code", "message" ], "type": "object", "properties": { "code": { "minLength": 1, "enum": [ "ACCESS_DENIED", "ARCHIVED_CONTENT_READ_ONLY", "ARCHIVE_ALREADY_ARCHIVED", "ARCHIVE_NOT_ARCHIVED", "BAD_REQUEST", "CONFLICT", "FEATURE_NOT_IN_LICENSE", "FEEDBACK_CLOSED", "FORBIDDEN", "INTERNAL_SERVER_ERROR", "LICENSE_LIMIT_EXCEEDED", "OPERATION_FAILED", "PERMISSION_DENIED", "PREMIUM_FEATURE_NOT_IN_LICENSE", "RESOURCE_NOT_FOUND", "TOO_MANY_REQUESTS", "UNAUTHORIZED", "UNRECOGNIZED_FIELD", "UNRECOGNIZED_FIELDS", "VALIDATION_ERROR" ], "type": "string", "description": "Machine-readable error code (e.g. VALIDATION_ERROR, RESOURCE_NOT_FOUND)." }, "message": { "minLength": 1, "type": "string", "description": "Human-readable error message." }, "field": { "type": "string", "description": "The request field that caused the error, if applicable.", "nullable": true }, "details": { "type": "string", "description": "Additional context about the error.", "nullable": true } }, "additionalProperties": false, "description": "Represents an error returned by the API." }, "ApiWarning": { "required": [ "code", "message" ], "type": "object", "properties": { "code": { "minLength": 1, "type": "string", "description": "Machine-readable warning code." }, "message": { "minLength": 1, "type": "string", "description": "Human-readable warning message." } }, "additionalProperties": false, "description": "Represents a non-fatal warning from the API." }, "AiQuerySource": { "type": "object", "properties": { "source_type": { "enum": [ "article", "pageCategory", "externalSource", "attachment" ], "type": "string", "allOf": [ { "$ref": "#/components/schemas/AiQuerySourceType" } ], "description": "Kind of source: `article`, `pageCategory`, `externalSource` or `attachment`.", "example": "article", "x-enumNames": [ "Article", "PageCategory", "ExternalSource", "Attachment" ], "x-enum-varnames": [ "Article", "PageCategory", "ExternalSource", "Attachment" ], "x-ms-enum": { "name": "AiQuerySourceType", "modelAsString": true } }, "citation_id": { "type": "string", "description": "Citation identifier of this source in the answer, when citations are enabled. Otherwise `null`.", "nullable": true, "example": "1" }, "article_id": { "type": "string", "description": "ID of the source article. For an attachment, the ID of the article that contains it. `null`\r\nfor page categories, for attachments in a page category, and for external sources.", "nullable": true, "example": "9a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d" }, "article_title": { "type": "string", "description": "Title of the source article.", "nullable": true, "example": "Configure SSO" }, "article_slug": { "type": "string", "description": "URL slug of the source article.", "nullable": true, "example": "configure-sso" }, "category_id": { "type": "string", "description": "ID of the category of the source, or of the page category itself.", "nullable": true, "example": "c5d6e7f8-9a0b-1c2d-3e4f-5a6b7c8d9e0f" }, "category_title": { "type": "string", "description": "Title of the category.", "nullable": true, "example": "Security" }, "category_slug": { "type": "string", "description": "URL slug of the category.", "nullable": true, "example": "security" }, "workspace_name": { "type": "string", "description": "Display name of the workspace that contains the source.", "nullable": true, "example": "v1" }, "workspace_slug": { "type": "string", "description": "URL slug of the workspace that contains the source.", "nullable": true, "example": "v1" }, "language_code": { "type": "string", "description": "Language code of the source content.", "nullable": true, "example": "en" }, "external_source_id": { "type": "string", "description": "ID of the external source. Set only when `source_type` is `externalSource`.", "nullable": true, "example": "3e4f5a6b-7c8d-9e0f-1a2b-3c4d5e6f7a8b" }, "external_source_name": { "type": "string", "description": "Name of the external source. Set only when `source_type` is `externalSource`.", "nullable": true, "example": "Product blog" }, "external_source_link": { "type": "string", "description": "Link to the external source. Set only when `source_type` is `externalSource`.", "nullable": true, "example": "https://example.com/blog/sso-setup" }, "attachment_title": { "type": "string", "description": "File name of the attachment. Set only when `source_type` is `attachment`.", "nullable": true, "example": "sso-setup-guide.pdf" }, "attachment_url": { "type": "string", "description": "URL of the attachment. Set only when `source_type` is `attachment`. For a private or mixed\r\nproject, the URL contains a time-limited, read-only access token. The token is scoped to the project's\r\nstorage container, not to this one file. Do not share the URL with users who must not read the\r\nproject's other files.", "nullable": true, "example": "https://cdn.document360.io/files/sso-setup-guide.pdf" } }, "additionalProperties": false, "description": "One source that the AI used to generate an answer." }, "AiQuerySourceType": { "enum": [ "article", "pageCategory", "externalSource", "attachment" ], "type": "string", "description": "Kind of content that an AI answer source refers to.", "x-enumNames": [ "Article", "PageCategory", "ExternalSource", "Attachment" ], "x-enum-varnames": [ "Article", "PageCategory", "ExternalSource", "Attachment" ], "x-ms-enum": { "name": "AiQuerySourceType", "modelAsString": true } } }, "securitySchemes": { "ApiKey": { "type": "apiKey", "description": "API key for machine-to-machine integrations, webhooks, and CI/CD (recommended). This is a static, pre-shared secret - treat it as an opaque string and do not parse it; it is an API key, not an OAuth 2.0 access token. Create one in the portal under **Settings > Knowledge base portal > API keys** using the **Create API key** button - this is a different credential from the V1/V2 *API token*, which lives on its own screen and will not authenticate a V3 request. The plaintext key (format `d360_sk_...`) is shown only once, at creation. Send it in the `X-API-Key` header: `X-API-Key: d360_sk_...`. Each key carries a fixed portal role, content role, and content-access scope, supports an optional expiry, and can be disabled or deleted at any time from the portal.", "name": "X-API-Key", "in": "header" }, "Bearer": { "type": "oauth2", "description": "All V3 endpoints require a Bearer token. Generate tokens in the Document360 portal under **Settings > API Tokens**. Tokens are project-scoped, require the `customerApi` scope, and do not expire by default. Tokens can be revoked at any time from the portal. Include the token in every request: `Authorization: Bearer