Skip to Content
APIEndpointsCreate knowledge document

Create knowledge document

Adds a document to the brand’s Knowledge Base from pasted text — the same as “Add Document -> Paste Text” in the app. Processing (summarize, chunk, embed) happens in the background: the document is returned with status: "processing". Poll Get knowledge document until it flips to ready or failed.

Requires the write:knowledge_base scope, and the workspace must be enabled for API writes.

POST /v1/brands/{brand_id}/knowledge-documents

Authorization

HeaderTypeRequired
AuthorizationBearer asky_sk_…required
Idempotency-Keystringrequired

Path parameters

ParameterTypeRequiredDescription
brand_iduuidrequiredFrom List brands

Body

application/json

FieldTypeRequiredDescription
titlestring, 1-200 charsrequired
user_descriptionstring, up to 2000 charsoptionalHow this document should be used, in your own words. Ignored (silently replaced) when writing_style_id is set
textstring, 1-1,000,000 charsrequiredPasted content, markdown or plain text. Roughly a 1MB cap, matching the app
writing_style_iduuidoptionalAttach as a writing-style reference document instead of general brand knowledge

Request

curl --request POST \ --url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/knowledge-documents' \ --header 'Authorization: Bearer <api-key>' \ --header 'Idempotency-Key: 5b0e77d2-13a9-4f6a-8ce1-9a3f5e21c0aa' \ --header 'Content-Type: application/json' \ --data '{"title": "Product Positioning FAQ", "user_description": "Internal FAQ used to ground content about our differentiation.", "text": "## What makes us different?\n\nAsky tracks how a brand appears across AI search engines and turns the gaps into content."}'

Response

{ "data": { "document": { "id": "b4f7e2a1-9c3d-4e6f-8a1b-2c5d7e9f0a3b", "brand_id": "242546de-4cee-4a7d-952e-f6aa60c63ef8", "title": "Product Positioning FAQ", "user_description": "Internal FAQ used to ground content about our differentiation.", "source_type": "paste", "status": "processing", "error_message": null, "char_count": 4820, "chunk_count": 0, "token_count": 0, "needs_reembed": false, "file_name": null, "page_count": null, "file_size_bytes": null, "mime_type": null, "material_type": null, "writing_style_id": null, "style_prompt_dismissed": false, "created_by": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "created_at": "2026-08-20T09:14:22.000Z", "updated_at": "2026-08-20T09:14:22.000Z" } }, "request_id": "req_7d21b0af59c34e18b6ac" }

Response fields

FieldTypeDescription
data.document.iduuidrequired. Use it with Get knowledge document
data.document.brand_iduuidrequired
data.document.titlestringrequired
data.document.user_descriptionstring | nullrequired
data.document.source_typestringrequired. Always paste for this endpoint
data.document.statusstringrequired. processing, ready or failed
data.document.error_messagestring | nullrequired. Set once status is failed
data.document.char_countintegerrequired. Length of the pasted text
data.document.chunk_countintegerrequired. Always 0 at creation, populated once ingest completes
data.document.token_countintegerrequired. Always 0 at creation, populated once ingest completes
data.document.needs_reembedbooleanrequired
data.document.file_namestring | nullrequired. Always null for a pasted-text document
data.document.page_countinteger | nullrequired. Always null for a pasted-text document
data.document.file_size_bytesinteger | nullrequired. Always null for a pasted-text document
data.document.mime_typestring | nullrequired. Always null for a pasted-text document
data.document.material_typestring | nullrequired. A content classification set once processing completes. null at creation
data.document.writing_style_iduuid | nullrequired
data.document.style_prompt_dismissedbooleanrequired
data.document.created_byuuidrequired
data.document.created_atstringrequired. ISO 8601
data.document.updated_atstringrequired. ISO 8601
request_idstringrequired. Also returned as the x-request-id header. Quote it when contacting support

Errors

StatusCodeWhen
400invalid_requestUnknown field, empty or over-200-character title, user_description over 2000 characters, empty or over-1,000,000-character text, or a writing_style_id that doesn’t exist or belongs to another brand
401invalid_tokenThe key is missing, malformed, or does not exist
401token_expiredThe key passed its expiry date
401token_revokedThe key was revoked
403insufficient_scopeThe key does not carry write:knowledge_base
403plan_requiredThis workspace is not enabled for API writes
403plan_requiredBrand Knowledge is not included in this workspace’s current plan
403quota_exceededThis document would push the workspace over its 50MB knowledge base storage limit
404not_foundThe brand does not exist, or this key is not allowed to reach it
429rate_limitedOver 60 requests per minute

plan_required appears twice with different messages. The first means this workspace’s plan does not include API writes at all. The second means writes are enabled but Brand Knowledge specifically is not on the plan.

Notes

writing_style_id overrides user_description. When you attach a document to a writing style, your user_description is ignored and replaced with an auto-generated description naming the style. There is a per-style cap on how many documents can be attached; going over it returns 400 invalid_request naming the reason.

The 50MB cap is on total knowledge base text, per workspace, not per document. It is checked against the UTF-8 byte length of text before anything is written, so a call that would tip the workspace over the limit fails cleanly with 403 quota_exceeded rather than partially writing.

Processing runs in the background. The document is returned with status: "processing" before summarizing, chunking and embedding have happened. Poll Get knowledge document until status flips to ready or failed.

A queue failure after the document is written still leaves the document behind. In the rare case where the background job cannot be queued, the call itself fails, but the document row persists with status: "failed" and an error_message pointing at asky_knowledge_document_resync. A caller polling by title rather than by the id from this response would still find it.

No URL or import ingestion here. This endpoint only covers pasted text; there is no PDF-free equivalent for a URL or a Notion-style import over this API. URL/scrape ingestion was removed from the app itself. Pulling one item from a connection Asky stored via OAuth (an MCP import) is also out of scope here, but if you already have your own access to that source, reading the content yourself and calling this endpoint gets you the same result.

Idempotency-Key is required. Reuse it when retrying an attempt and the original response is replayed rather than a second document being created. See Idempotency.

Last updated on