Skip to Content
APIEndpointsCreate knowledge document from PDF

Create knowledge document from PDF

Adds a document to the brand’s Knowledge Base from a PDF file. One call: the file is uploaded and vision-extracted to text automatically, matching what a PDF upload through the app does. file_base64 is capped at 25MB decoded. Processing 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/pdf

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
file_base64stringrequiredThe PDF file, base64-encoded. 25MB cap on the decoded bytes
file_namestring, up to 255 charsoptionalDefaults to the document id
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/pdf' \ --header 'Authorization: Bearer <api-key>' \ --header 'Idempotency-Key: 5b0e77d2-13a9-4f6a-8ce1-9a3f5e21c0aa' \ --header 'Content-Type: application/json' \ --data '{"title": "2026 Product Spec Sheet", "user_description": "Official spec sheet for the enterprise tier.", "file_base64": "JVBERi0xLjQKJ...", "file_name": "product-spec-2026.pdf"}'

Response

{ "data": { "document": { "id": "d9e3a1c7-4f8b-4a2d-9c01-7e5f3b9a2d68", "brand_id": "242546de-4cee-4a7d-952e-f6aa60c63ef8", "title": "2026 Product Spec Sheet", "user_description": "Official spec sheet for the enterprise tier.", "source_type": "pdf", "status": "processing", "error_message": null, "char_count": 0, "chunk_count": 0, "token_count": 0, "needs_reembed": false, "file_name": "product-spec-2026.pdf", "page_count": null, "file_size_bytes": 812044, "mime_type": "application/pdf", "material_type": null, "writing_style_id": null, "style_prompt_dismissed": false, "created_by": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "created_at": "2026-08-20T09:20:11.000Z", "updated_at": "2026-08-20T09:20:11.000Z" } }, "request_id": "req_2b8f1a0c9e3d47f5a6b8" }

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 pdf for this endpoint
data.document.statusstringrequired. processing, ready or failed
data.document.error_messagestring | nullrequired. Set once status is failed
data.document.char_countintegerrequired. 0 until vision extraction completes
data.document.chunk_countintegerrequired. 0 until vision extraction completes
data.document.token_countintegerrequired. 0 until vision extraction completes
data.document.needs_reembedbooleanrequired
data.document.file_namestringrequired
data.document.page_countinteger | nullrequired. null until vision extraction completes
data.document.file_size_bytesintegerrequired. Size of the decoded PDF, in bytes
data.document.mime_typestringrequired. Always application/pdf
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, file_base64 that isn’t valid base64, a decoded file that is empty, a decoded file over 25MB, a decoded file whose first bytes aren’t %PDF, 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_exceededThe workspace is already at 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

This is one call, not a two-step upload. The app’s browser flow signs a Storage URL, uploads from the client, then confirms — built that way to keep large files off the Next.js server. That constraint doesn’t apply to a server-to-server call, so this endpoint just accepts the file’s raw bytes in file_base64 and writes them to Storage itself with a service-role client.

The 25MB cap is on the decoded PDF, not the request body. Base64 inflates the wire size by roughly a third, so the JSON body you send will be noticeably larger than 25MB for a file near the limit. Budget for that if you enforce a request-size ceiling on your own side.

Extraction is vision-based and asynchronous. The document is returned with status: "processing" and char_count: 0, page_count: null before extraction has run. Poll Get knowledge document and read raw_text, char_count and page_count once status flips to ready.

Workspace storage is checked up front, before the upload. The PDF’s file bytes themselves don’t count against the 50MB knowledge base cap, only its extracted text will, once ingested. A workspace already at the cap is still rejected before the upload happens, so you’re not charged for an upload and a vision extraction that would fail regardless.

writing_style_id overrides user_description, the same as on Create knowledge document: your value is replaced with an auto-generated description naming the style, and the per-style document cap still applies.

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

Last updated on