Skip to content

Document Management ​

Once a document is ingested into an index4.ai project, three admin endpoints let you manage it:

EndpointPurpose
GET /docsList all documents in the project namespace.
GET /docs/{docId}Get metadata for one document.
DELETE /docs/{docId}Remove a document's vectors and storage from the namespace.

All three accept a project API key; account-level credentials work too when you send X-Project-ID, unless the project is protected (Authentication).

List documents ​

bash
curl -sS "https://api.index4.ai/v1/docs" \
  -H "authorization: Bearer $INDEX4AI_API_KEY" | jq .

Response (ListDocsResponse):

json
{
  "namespace": "project_docs_rag_4f2",
  "total_documents": 3,
  "documents": [
    {
      "doc_id": "annual-report-2025",
      "title": "Annual Report 2025",
      "language": "en",
      "filename": "annual-report.pdf",
      "canonical_url": "https://investors.example.com/2025/annual-report",
      "pages": 84,
      "chunkset_count": 142,
      "chunk_count": 612,
      "image_count": 38,
      "table_count": 14,
      "ingested_at": "2026-04-30T10:00:00Z",
      "source_job_id": "550e8400-…",
      "bm25_state": "ready"
    },
    …
  ]
}

The documents array is the authoritative source for doc_id values. Use the exact doc_id string in doc_filter (on /search) and as the {docId} path parameter on the per-doc endpoints.

source_job_id ties the document back to the /ingest job that created it — useful for audit and incident replay.

Inspect one document ​

bash
curl -sS "https://api.index4.ai/v1/docs/annual-report-2025" \
  -H "authorization: Bearer $INDEX4AI_API_KEY" | jq .

Response (DocInfo):

json
{
  "doc_id": "annual-report-2025",
  "title": "Annual Report 2025",
  "language": "en",
  "filename": "annual-report.pdf",
  "canonical_url": "https://investors.example.com/2025/annual-report",
  "pages": 84,
  "chunkset_count": 142,
  "chunk_count": 612,
  "image_count": 38,
  "table_count": 14,
  "ingested_at": "2026-04-30T10:00:00Z",
  "source_job_id": "550e8400-…",
  "bm25_state": "ready"
}

The same shape as a single entry from GET /docs. Field semantics:

FieldMeaning
doc_idStable identifier within this project namespace.
titleDetected from document metadata when present, otherwise from filename.
languageDetected primary language (BCP-47 short code).
filenameThe original Content-Disposition filename at ingest.
canonical_urlCitation URL stamped by Core at ingest — e.g. the resolved target when ingesting from a short link / redirect. Empty when not applicable.
pagesSource page count (when applicable).
chunkset_count / chunk_countHow many chunksets and chunks were extracted. Useful for sanity-checking the pipeline.
image_count / table_countNumber of figures and tables index4.ai identified.
ingested_atUTC timestamp the ingest job completed.
source_job_idThe job_id returned by the original POST /ingest.
bm25_stateState of the document's BM25 (lexical) index.
attributes / attribute_schemaThe typed attributes attached at ingest, and their declared types (see Ingestion).

Delete a document ​

bash
curl -sS -X DELETE "https://api.index4.ai/v1/docs/annual-report-2025" \
  -H "authorization: Bearer $INDEX4AI_API_KEY" | jq .

Response (DeleteDocResponse):

json
{
  "doc_id": "annual-report-2025",
  "vectors_deleted": 612,
  "storage_deleted": true
}

DELETE is destructive and scoped:

  • Destructive. All vectors and storage for this document are removed. Subsequent /search calls will not surface its content.
  • Scoped. Only the document is removed. The project, project API key, and all other documents are left untouched.

If you want to reset the entire project namespace at once, delete and recreate the project — see Create a project. (Deleted projects can be restored; see that page.)

Common patterns ​

Garbage-collect old docs by ingest date.

bash
curl -sS "https://api.index4.ai/v1/docs" -H "authorization: Bearer $INDEX4AI_API_KEY" \
| jq -r '.documents
         | map(select(.ingested_at < "2026-01-01T00:00:00Z"))
         | .[].doc_id' \
| xargs -I{} curl -sS -X DELETE "https://api.index4.ai/v1/docs/{}" \
                -H "authorization: Bearer $INDEX4AI_API_KEY"

Replace a doc with a fresh version.

bash
# 1. delete the old version
curl -sS -X DELETE "https://api.index4.ai/v1/docs/annual-report-2025" \
  -H "authorization: Bearer $INDEX4AI_API_KEY"

# 2. ingest the new file
curl -sS -X POST "https://api.index4.ai/v1/ingest" \
  -H "authorization: Bearer $INDEX4AI_API_KEY" \
  -H "content-type: application/octet-stream" \
  -H 'content-disposition: attachment; filename="annual-report-2025.pdf"' \
  --data-binary @annual-report-2025.pdf

This pattern is safer than relying on re-ingest replacement, because the docId derivation is filename-sensitive — explicit delete-then-ingest avoids surprises if the filename changes between versions.

From the Python SDK ​

All three admin operations are typed methods on the Index4AI client:

python
from index4ai import Index4AI

g = Index4AI()

# List
docs = g.list_docs()                            # list[DocInfo]
for d in docs:
    print(d.doc_id, d.filename, d.pages, d.source_job_id)

# Inspect one
info = g.get_doc("annual-report-2025")          # DocInfo

# Delete one
result = g.delete_doc("annual-report-2025")     # DeleteDocResponse
print(result.vectors_deleted, result.storage_deleted)

DocInfo and DeleteDocResponse are dataclasses — the fields match the JSON shapes documented above. To garbage-collect old docs:

python
from datetime import datetime, timezone
from index4ai import Index4AI

cutoff = datetime(2026, 1, 1, tzinfo=timezone.utc)
g = Index4AI()
try:
    for d in g.list_docs():
        if datetime.fromisoformat(d.ingested_at) < cutoff:
            g.delete_doc(d.doc_id)
finally:
    g.close()

Full surface: Index4AI.list_docs / Index4AI.get_doc / Index4AI.delete_doc. Async equivalents on AsyncIndex4AI.

Errors ​

StatusCauseNotes
400Empty docId path parameterProvide the exact doc_id from DocInfo.
401Missing/invalid Bearer tokenUse a project API key.
404Doc is not in this project namespaceConfirm with GET /docs. Document is project-scoped.
502 / 503Upstream / proxy errorRetry with backoff.

Next ​

  • API reference — full request/response shapes for every endpoint.