PageIndex Document Processing
Index documents, read their content, and organize your library using your configured client.
- Index a document — upload a file and get its
doc_id. - Read a document — check status, retrieve the tree, or read pages.
- Manage documents — list or delete documents.
- Folders (cloud) — organize and browse documents by folder.
Operations work in both index modes unless marked (cloud).
Index a document
Index a document and get back a doc_id used by every other operation.
result = client.submit_document("./2023-annual-report.pdf")
doc_id = result["doc_id"]
Example Response
{
"doc_id": "pi-abc123def456",
"name": "2023-annual-report.pdf"
}
name is the stored document name. A name already in use gains a numeric suffix (name_1 … name_99) and a UserWarning is emitted.
Cloud accepts PDF, PPTX, and Word. Uploads process asynchronously — either block with wait=True, or submit many documents and poll afterwards.
# Block until ready
doc_id = client.submit_document("./report.pdf", wait=True)["doc_id"]
# Or poll yourself
doc_id = client.submit_document("./report.pdf")["doc_id"]
if client.get_document(doc_id)["status"] == "completed":
print("Document processing completed")
Pass mode="flash" to build the tree with PageIndex Flash, from the PDF's text layer:
doc_id = client.submit_document("./report.pdf", mode="flash")["doc_id"]
Local mode accepts PDF only. The call finishes indexing before returning and stores the document under storage_path.
doc_id = client.submit_document("./report.pdf")["doc_id"]
submit_document() parameters
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| file_path | string | yes | Local path to the file. Cloud accepts PDF, PPTX, and Word; local mode accepts PDF only. | - |
| mode | string | no | Local: "flash" (default) or "standard", a full LLM-built tree. Cloud: None (default), the OCR-based cloud pipeline, or "flash". | None |
| wait | boolean | no | Return only once the document is ready. Cloud: polls until "completed". Local: indexing is already synchronous. | False |
| folder_id | string | no | Cloud-only — folder ID. | None |
Read a document
If you have a document name, use get_document_id() to look up its ID before reading it:
doc_id = client.get_document_id("report.pdf")
doc_id = client.get_document_id("Research/Papers/report.pdf") # a path works too
A path is accepted as well as a bare name: the folder part is stripped, because document names are unique across a library. This raises PageIndexAPIError if no document with that name exists.
meta = client.get_document(doc_id)
print(f"{meta['name']}: {meta['status']}, {meta['pageNum']} pages")
get_document() response fields
| Field | Type | Description |
|---|---|---|
| id | string | Document ID |
| name | string | Document filename |
| description | string | Document description (if available) |
| status | string | "queued", "processing", "completed", or "failed" |
| createdAt | string | Creation timestamp, UTC with no timezone marker |
| pageNum | int | Number of pages |
| folderId | string | Folder the document belongs to (always None in local mode) |
Display creation time in your timezone
To display createdAt in the user's timezone:
from datetime import datetime, timezone
datetime.fromisoformat(meta["createdAt"]).replace(tzinfo=timezone.utc).astimezone()
get_tree() includes node text by default (include_text=True), with summaries off (node_summary=False). For a compact tree with summaries and no node text, set both options explicitly:
tree_result = client.get_tree(doc_id, node_summary=True, include_text=False)
if tree_result.get("status") == "completed":
print("PageIndex Tree Structure:", tree_result.get("result"))
Example Response (Processing)
{
"doc_id": "pi-abc123def456",
"status": "processing"
}
Example Response (Completed)
{
"doc_id": "pi-abc123def456",
"status": "completed",
"result": [
{
"title": "Financial Stability",
"node_id": "0006",
"page_index": 21,
"prefix_summary": "The Federal Reserve maintains financial stability through comprehensive monitoring...",
"nodes": [
{
"title": "Monitoring Financial Vulnerabilities",
"node_id": "0007",
"page_index": 22,
"summary": "The Federal Reserve's monitoring focuses on identifying and assessing potential risks..."
},
{
"title": "Domestic and International Cooperation and Coordination",
"node_id": "0008",
"page_index": 28,
"summary": "In 2023, the Federal Reserve collaborated internationally with central banks..."
}
]
}
]
}
With node_summary=True, leaf nodes carry summary and nodes with children carry prefix_summary. With
include_text=True, each node also carries a text field.
Local documents are always "completed" by the time submit_document returns.
get_tree() parameters
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| doc_id | string | yes | Document ID | - |
| node_summary | boolean | no | Include a summary for each node. | False |
| include_text | boolean | no | Include node text. Set to False for a smaller response. | True |
Read the text of specific pages.
pages = client.get_page_content(doc_id, "5-7")
for page in pages:
print(page["page_index"], page["markdown"][:200])
The full extraction is also available through get_ocr(doc_id, format=...), which returns page-based ("page"), node-based ("node"), or concatenated ("raw") markdown.
get_page_content() parameters
| Name | Type | Required | Description |
|---|---|---|---|
| doc_id | string | yes | Document ID |
| pages | string | yes | Page specifier — "5-7", "3,8", or "12" |
Read a block (cloud)
One layout block with its bounding box — the block behind a block="…" citation. Cloud documents indexed since September 13, 2026 carry blocks, except those indexed with Flash; a document without them returns 404 here until it is re-indexed.
block = client.get_block(doc_id, "p3_text_5")
Example Response
{
"doc_id": "pi-abc123def456",
"page": 3,
"block_id": "p3_text_5",
"bbox": [78, 24, 293, 44],
"block_type": "text",
"text": "..."
}
bbox is [x0, y0, x1, y1] in thousandths of the page's width and height, origin top-left.
Manage documents
Paginated list of indexed documents, newest first.
Returns: an object with documents (array of document metadata), total, limit, and offset.
Each document includes id, name, description, status, createdAt, pageNum, folderId, metadata, features, and path (the folder chain as "Parent/Child", or null when the document is unfiled or in local mode).
result = client.list_documents(limit=10)
For the next page, pass offset=10:
result = client.list_documents(limit=10, offset=10)
list_documents() parameters
| Name | Type | Description | Default |
|---|---|---|---|
| limit | int | Maximum documents to return (1–10,000) | 50 |
| offset | int | Number of documents to skip | 0 |
| folder_id | string | Cloud-only — filter by folder | None |
| recursive | bool | Cloud-only — also include documents in that folder's subfolders, flattened into one list | False |
Permanently delete a document and all its associated data.
client.delete_document(doc_id)
Example Response
{ "message": "Document deleted successfully." }
delete_document() parameters
| Name | Type | Required | Description |
|---|---|---|---|
| doc_id | string | yes | Document ID |
Folders (cloud)
Organize documents into folders and nested subfolders. Folders created without a parent and documents uploaded without a folder are placed at the root.
result = client.create_folder("Research Papers", description="2024 research papers")
folder_id = result["folder"]["id"]
With no parent_folder_id, the folder is created at the root — that is why the
response below has "parent_folder_id": null.
With Parent Folder (nested)
result = client.create_folder("Q1 Reports", parent_folder_id="my-folder-id")
Example Response
{
"folder": {
"id": "my-folder-id",
"name": "Research Papers",
"description": "2024 research papers",
"parent_folder_id": null,
"created_at": "2024-06-15 10:30:00",
"file_count": 0,
"children_count": 0
}
}
create_folder() parameters
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| name | string | yes | Folder name | - |
| description | string | no | Folder description | None |
| parent_folder_id | string | no | Parent folder ID for nesting. Omit to create at the root. | None |
Assign a document to a folder during upload:
result = client.submit_document("./report.pdf", folder_id="my-folder-id")
Filter documents by folder. Omit folder_id to list all documents; "root" returns documents not assigned to a folder.
# List documents in a specific folder
docs = client.list_documents(folder_id="my-folder-id")
# List all documents (no folder filter)
docs = client.list_documents()
# List documents not assigned to any folder
docs = client.list_documents(folder_id="root")
# With pagination
docs = client.list_documents(folder_id="my-folder-id", limit=10, offset=20)
List your folders, optionally filtered by parent.
# List all folders
result = client.list_folders()
# List only root-level folders
result = client.list_folders(parent_folder_id="root")
# List subfolders of a specific folder
result = client.list_folders(parent_folder_id="my-folder-id")
Example Response
{
"folders": [
{
"id": "my-folder-id",
"name": "Research Papers",
"description": "2024 research papers",
"parent_folder_id": null,
"created_at": "2024-06-15T10:30:00",
"updated_at": "2024-06-15T10:30:00",
"file_count": 5,
"children_count": 2
}
],
"total": 1
}
Paths
A document or folder's place in the library, as a readable path — and the reverse lookup:
client.get_document_path(doc_id) # "Research/Papers/attention.pdf"
client.get_folder_path(folder_id) # "Research/Papers"
client.get_folder_id("Research/Papers") # the folder's ID
get_document_path() works in both modes, returning just the name for a document at the library root or a local one. The two folder calls are cloud-only. Feed a document path straight back to get_document_id().
To ask questions within a folder, pass folder_id to LLM Integration, or use folder_context() with Agent Integration. For chat, "root" means the whole library; for document listing, it means only documents outside folders.
list_folders() parameters
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| parent_folder_id | string | no | "root" for root-level only, a folder ID for subfolders, or omit for all | None |