Add documents
Upload files, hand over a URL, send text or a web page, upload in batches, and follow processing until a document is ready.
Every document goes through POST /v1/{knowledge_id}/documents (or its batch form). The call returns at once with an object_id and status: "processing"; the document is read, split into sections, indexed and has its fields extracted in the background.
Ways to add a document
POST /v1/{knowledge_id}/documents is a multipart/form-data request. Send exactly one of:
| Field | Use it for |
|---|---|
file | A file upload, up to 5 MB. |
file_url | A URL the service downloads from — for example an upload URL from the next section, or a file on your own storage. |
text | Plain text you already have. |
weblink | A web page to fetch and read (max_depth, default 1, follows links from it). |
Optional fields:
| Field | Meaning |
|---|---|
document_processing_mode | auto (default), text_based, scanned, layout_aware, visual or mixed — how pages are read. Leave it on auto unless a document comes out badly. |
chunk_size | Section length in characters (default 2000). |
extra_metadata | A JSON object of your own fields stored with the document, for example {"customer_id": "C-1042"}. |
extra_metadata.source_id + last_modified | Your own id and version for the document. Sending the same source_id again with a newer last_modified re-reads it in place instead of adding a duplicate. |
Accepted files and limits
| Types | PDF, DOCX, TXT, Markdown, HTML; MP3, WAV, AAC and OGG audio (transcribed) |
Direct upload (file) | 5 MB per file |
| PDF and DOCX | 10 pages per document |
| Text formats | 100,000 characters per document |
Files over a limit, and unsupported types such as CSV, are refused with 400 and a detail saying why.
Uploading through an upload URL
For files you would rather not stream through your server — or that are larger than the 5 MB direct-upload limit — ask for a pre-signed upload URL, put the bytes there, and then add the document by URL:
POST /v1/{knowledge_id}/upload-urlwith form fieldsfile_nameandcontent_type. The response haspresigned_url(for the upload),download_presigned_urlandobject_id.PUTthe file topresigned_urlwith the sameContent-Type, within 5 minutes.POST /v1/{knowledge_id}/documentswithfile_urlset todownload_presigned_url.
import os
import requests
API_ROOT = "https://futuresmart.ai/document-intelligence/api"
COLLECTION_ID = os.environ["DOCUMENT_INTELLIGENCE_COLLECTION_ID"]
HEADERS = {"x-api-key": os.environ["DOCUMENT_INTELLIGENCE_API_KEY"]}
slot = requests.post(
f"{API_ROOT}/v1/{COLLECTION_ID}/upload-url",
headers=HEADERS,
data={"file_name": "invoice.pdf", "content_type": "application/pdf"},
timeout=60,
)
slot.raise_for_status()
slot = slot.json()
with open("invoice.pdf", "rb") as f:
requests.put(slot["presigned_url"], data=f, headers={"Content-Type": "application/pdf"}, timeout=300).raise_for_status()
added = requests.post(
f"{API_ROOT}/v1/{COLLECTION_ID}/documents",
headers=HEADERS,
data={"file_url": slot["download_presigned_url"]},
timeout=120,
)
added.raise_for_status()
print(added.json())SLOT=$(curl -sS -X POST "https://futuresmart.ai/document-intelligence/api/v1/$DOCUMENT_INTELLIGENCE_COLLECTION_ID/upload-url" \
-H "x-api-key: $DOCUMENT_INTELLIGENCE_API_KEY" \
-F file_name=invoice.pdf -F content_type=application/pdf)
PUT_URL=$(echo "$SLOT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["presigned_url"])')
GET_URL=$(echo "$SLOT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["download_presigned_url"])')
curl -sS -X PUT "$PUT_URL" -H "Content-Type: application/pdf" --data-binary @invoice.pdf
curl -sS -X POST "https://futuresmart.ai/document-intelligence/api/v1/$DOCUMENT_INTELLIGENCE_COLLECTION_ID/documents" \
-H "x-api-key: $DOCUMENT_INTELLIGENCE_API_KEY" \
-F "file_url=$GET_URL"The page and character limits still apply to documents added by URL.
Text and web pages
curl -sS -X POST "https://futuresmart.ai/document-intelligence/api/v1/$DOCUMENT_INTELLIGENCE_COLLECTION_ID/documents" \
-H "x-api-key: $DOCUMENT_INTELLIGENCE_API_KEY" \
-F "text=Northwind standard terms: invoices are payable within 30 days."
curl -sS -X POST "https://futuresmart.ai/document-intelligence/api/v1/$DOCUMENT_INTELLIGENCE_COLLECTION_ID/documents" \
-H "x-api-key: $DOCUMENT_INTELLIGENCE_API_KEY" \
-F "weblink=https://example.com/pricing"Processing status
GET /v1/{knowledge_id}/documents/{object_id}/status returns {knowledge_id, object_id, status, error_detail}. A document moves through some of these states:
| Status | Meaning |
|---|---|
processing, scraping, extracting, indexing, enriching | Still being read. Keep polling — every 3–5 seconds is plenty. |
completed | Searchable, and its fields are extracted. |
failed | Could not be read; error_detail says why (for example a scanned PDF with no text). |
invalid | Refused before processing, for example a URL that could not be downloaded. |
import os
import time
import requests
API_ROOT = "https://futuresmart.ai/document-intelligence/api"
COLLECTION_ID = os.environ["DOCUMENT_INTELLIGENCE_COLLECTION_ID"]
HEADERS = {"x-api-key": os.environ["DOCUMENT_INTELLIGENCE_API_KEY"]}
def add_and_wait(path, timeout_s=600):
with open(path, "rb") as f:
r = requests.post(f"{API_ROOT}/v1/{COLLECTION_ID}/documents", headers=HEADERS, files={"file": f}, timeout=120)
r.raise_for_status()
object_id = r.json()["object_id"]
deadline = time.time() + timeout_s
while time.time() < deadline:
status = requests.get(
f"{API_ROOT}/v1/{COLLECTION_ID}/documents/{object_id}/status", headers=HEADERS, timeout=60
).json()
if status["status"] in ("completed", "failed", "invalid"):
return status
time.sleep(4)
raise TimeoutError(f"{path} still processing after {timeout_s}s")
print(add_and_wait("invoice.pdf"))GET /v2/{knowledge_id}/documents lists every document with its status, file name and source, paginated (page, page_size).
Batches
To add up to 50 files at once, send them together to POST /v1/{knowledge_id}/documents/batch (files repeated, and/or a comma-separated file_urls), then follow GET /v1/{knowledge_id}/batch/{batch_id}/status, which reports total, completed, processing, failed and each document. For upload URLs in bulk, POST /v1/{knowledge_id}/upload-urls/batch takes {"files": [{"file_name", "content_type"}, …]}. See the Batch upload reference.
Deleting a document
DELETE /v1/{knowledge_id}/documents/{object_id} removes the document, its sections and its extracted fields. Deletion runs in the background; GET …/documents/{object_id}/deletion-status reports deleting, completed or error.