https://api.decisionnode.com /v1/collections/{id}/itemscurl -X POST https://api.decisionnode.com/v1/collections/col_3f6c1a9e0b2d4c7f8a1e5d9b2c4f6a80/items?wait=true \
-H "Authorization: Bearer $DECISIONNODE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Claims policy 2026","text":"# Claims policy 2026\n\n## Receipts\n\nReject any claim over 500 SEK without a receipt.\n\n## Photos\n\nPhotos of damage must show the date they were taken.","format":"markdown","reference":"policy-2026","pinned":true}'Headers#
AuthorizationheaderrequiredBearer dn_live_.... A Full access key: every call acts for that key's workspace only, and a Decisions-only key gets403key_scope_denied, "This key may only make decisions."Content-Typeheaderapplication/json. Not checked: the body is read as JSON whatever its type.Idempotency-Keyheader- 1 to 255 printable ASCII characters of your choosing, sent once. A retry with the same key, route and body within 24 hours gets the first answer again; see Retrying.
Path parameters#
idstringrequired- The collection:
col_and 32 hex digits for your own, or a public collection's name,celebrities.
Query parameters
waitbooleandefaultfalse- Wait up to 10 seconds for the document to be ready.
Request body#
titlestringrequired- 1 to 200 characters.
textstringrequired- UTF-8 without NUL, up to 512 KiB once stored.
formatstringdefault"markdown"markdown(cut at its headings) ortext(cut at its paragraphs).referencestring- 1 to 64 characters of
A-Z,a-z,0-9and_ . : -, unique in the knowledge base. Left out, the document's ownitm_id. pinnedbooleandefaultfalse- Give the document to every request of the knowledge base. See Pinned documents.
pin_rankintegerdefault0- 0 to 1,000, lowest first.
labelstring- Up to 128 characters.
metadataobject- Up to 20 flat fields, as an item's metadata. On a scoped knowledge base, the scope key's value, a text; left out, the document is global.
A file#
Presign the file with POST /v1/uploads and "purpose": "knowledge" (PDF, Word, PowerPoint, Excel, HTML, Markdown, text or an image, up to 50 MB; a Full access key), PUT its bytes, then send upload_id in place of text: {"upload_id": "upl_...", "title"?, "reference"?, "pinned"?, "pin_rank"?, "label"?, "metadata"?}. title defaults to the file name without its extension; text or format beside upload_id is a 422. The upload is used up by the document. The answer is a file document, processed as a console upload: read, cut into passages, indexed, and the file deleted once its text is read.
Response#
202 Accepted with the document queued. With ?wait=true, 201 Created once it is ready, or 202 as it stands after 10 seconds. Poll Retrieve an item until status is ready or failed. Indexing is billed for the new tokens once the document is ready; see Pricing.
{
"id": "itm_9a1c4e7b2d5f8a0c3e6b9d2f5a8c1e4b",
"title": "Claims policy 2026",
"reference": "policy-2026",
"format": "markdown",
"label": null,
"metadata": {},
"pinned": true,
"pin_rank": 0,
"source": "article",
"file": null,
"status": "queued",
"stage": null,
"progress": null,
"serving": "none",
"error": null,
"delayed": false,
"warnings": [],
"chunks": 0,
"tokens": 0,
"content_sha256": "5d41402abc4b2a76b9719d911017c5925d41402abc4b2a76b9719d911017c592",
"version": 1,
"queued_at": "2026-10-20T11:00:04Z",
"ready_at": null,
"created_at": "2026-10-20T11:00:04Z"
}The document
idstringitm_and 32 hex digits.title, reference, format, label, metadata, pinned, pin_rankas sent- As you sent them;
referenceandlabelnullwhen not set. sourcestringarticlefor a document written as text,filefor one made from a file, through the API or the console.fileobject or null- A file's
filename,content_type,byte_size,pagesandoriginal_held(truewhile the uploaded file is still kept: until its text has been read successfully);nullfor an article. statusstring- Of the newest version:
uploading(a console file not yet arrived),queued,processing,readyorfailed. stage, progressstring or null, object or null- While
processing:stageextracting(files only),chunkingorembedding, andprogresswithchunks_embedded,chunks_totaland, for a PDF,pages; bothnullotherwise. servingstringcurrent(the newest version answers requests),previous(an older one does, while the newest is processed or after it failed) ornone.errorstring or null- On a failed version:
pinned_budget_exceeded,chunks_limit_reachedorembedding_rejected. delayedbooleantrueonce it has waited over 15 minutes because indexing is unavailable on our side; never a failure.warningsarraypossible_secret,possible_instruction: shown to you, changing nothing.chunks, tokensinteger- Its passages and their tokens, of the version that answers.
content_sha256string- SHA-256 of the stored text, format and title: the same document sent again has the same one.
versioninteger- Rises with every new text or title.
queued_at, ready_at, created_atstring- RFC 3339;
ready_atnulluntil a version is ready. textstring or null- With
?include=textonly: the stored text of the version that answers,nullwhile none does.
Errors#
| Status | Type | When | What to do |
|---|---|---|---|
400 | api_usage_error | A malformed Idempotency-Key: "Idempotency-Key must be sent once, as 1 to 255 printable ASCII characters." | Send one key of 1 to 255 printable ASCII characters |
401 | authentication_error | The key is missing, unknown or revoked | Check the Authorization header |
402 | insufficient_credit | "Add credit to store more knowledge.": the balance cannot pay and the free allowance does not cover the write; on the free tier details.reason is free_text_chunks or free_text_tokens, with resets_at | Add credit, or wait for resets_at |
403 | key_scope_denied | A Decisions-only key: "This key may only make decisions." | Use a Full access key on your server |
403 | booster_not_enabled | Knowledge is turned off for your workspace | Write to us |
403 | collections_region_unavailable | Your workspace's storage location is not the default | Write to us |
404 | collection_not_found | No such collection for your workspace; another workspace's reads the same. "Collection not found: <id>.", the id repeated only when it has the form of one | Check the id |
400 | collection_type_mismatch | The collection is a face collection: a face body to a knowledge base, or a document to a face collection | Use a knowledge base's id |
409 | reference_taken | "Another item of this collection has this reference."; details.item_id names it | Use another reference, or PUT that document |
409 | pinned_budget_exceeded | Pinning this, or its new text, would take the pinned documents past their cap (512 tokens by default) | Shorten or unpin a pinned document |
409 | chunks_limit_reached, items_limit_reached | Your workspace's passages or items are at their limit | Delete documents, or write to us |
409 | idempotency_key_reused, idempotency_in_progress | The key was used with another request, or its first request still runs (Retry-After: 1) | See Retrying |
400 | upload_not_found, upload_expired, upload_consumed, upload_incomplete, upload_purpose_mismatch | The upload_id is unknown, past its hour, already a document's, has no bytes of the declared size yet, or is an image upload | Presign and upload the file again, or finish its PUT |
413 | item_too_large | The text is over 512 KiB once stored | Split the document |
422 | a detail list | A field out of bounds; invalid_text for a text that is not UTF-8 or holds a NUL; text or format beside an upload_id; an image in the body | Fix the field; a 422 frees the Idempotency-Key |
422 | a detail list | The body is not JSON (json_invalid) | Send a JSON object |
429 | rate_limit_error | "This workspace has reached its ingestion rate. Retry later.": details.reason ingest_queue_full (1,000 documents waiting) or ingest_tokens_per_hour (2,000,000 newly indexed tokens within the hour) | Wait Retry-After (or retry-after-ms), then send it again |
500 | api_error | A fault on our side | Retry with backoff |
529 | overloaded_error | details.reason enrollment_unpriced: "Text ingestion is not available on this deployment yet." | Never retried; write to us |
529 | overloaded_error | The collections cannot take the call right now | Wait Retry-After (1 s, or 1 to 2 s when the key store is busy), then retry |
A refusal is {"detail": {"error_type": "...", "message": "..."}}; a 422 is {"detail": [...]}, one entry per field, each with type, loc, msg and input (a string cut to 64 characters, an object or array never echoed). Every 429 and 529 and the 409 idempotency_in_progress carry Retry-After (seconds) and retry-after-ms (milliseconds); enrollment_unpriced carries neither. The Collections API's own refusals (api_usage_error, collection_read_only, item_not_found, collections_region_unavailable, the limits, the idempotency 409s and image_url_refused) also carry x-decisionnode-error, the message in ASCII. Retry 408, 429, 529 and any 5xx after Retry-After; fix the call for the other 4xx.