Index4AI Client API Reference
from index4ai import Index4AIIndex4AI is the synchronous client for index4.ai (RAG / hybrid search). It is project-scoped and validates its API key prefix locally — see Authentication below.
For async code, use AsyncIndex4AI.
Constructor
Index4AI(
api_key: str | None = None,
*,
timeout: float = 600.0,
client: httpx.Client | None = None,
)| Parameter | Default | Notes |
|---|---|---|
api_key | None | Reads INDEX4AI_API_KEY if omitted. Must start with poma_proj_gr_. Account keys (poma_acc_…) are rejected locally. |
timeout | 600.0 | HTTP timeout in seconds, passed through to httpx. |
client | None | Pre-built httpx.Client to reuse a connection pool. Bearer header is set by the SDK either way. |
The API host defaults to https://api.index4.ai and can be overridden with INDEX4AI_API_BASE_URL. Requests go to API version 1 (/v1).
Raises InvalidApiKeyError when the resolved key is missing, has the account prefix, or has any other unexpected prefix.
Authentication
index4.ai requires a project-level key. The Bearer token is bound to one project namespace — every ingest, every search, every list goes against that namespace.
import os
os.environ["INDEX4AI_API_KEY"] = "poma_proj_gr_…"
from index4ai import Index4AI
client = Index4AI()Full provisioning flow: Authentication.
Ingest methods
submit
submit(
file_path: str | os.PathLike[str] | None = None,
*,
remote_url: str | None = None,
base_url: str | None = None,
completion: str | None = None,
attributes: dict[str, Any] | None = None,
attribute_schema: dict[str, Any] | None = None,
) -> strSubmit a document to index4.ai ingestion. Returns the job_id. Use this when you want to capture the job ID and collect later.
| Parameter | Effect |
|---|---|
file_path | Local file to upload. Pass exactly one of file_path or remote_url; otherwise ValueError. |
remote_url | Public URL the server fetches itself — nothing is uploaded. |
base_url | Used by HTML inputs to resolve relative links against a known origin. |
completion | Completion webhook, "<url>|<header>:<value>|...", capped at 1024 characters. |
attributes | Typed attributes stored with the document, usable as attribute_filters at query time. string, int, float and bool are inferred. |
attribute_schema | Declares attribute types that cannot be inferred, such as {"published_at": {"type": "datetime"}} (datetime, encrypted_text). |
Attribute names are permanent per project: call list_attributes() first and reuse an existing name.
Raises SubmitUncertainError if the connection fails mid-submit (a job may or may not exist — check list_docs() before re-submitting) and ApiError on a non-2xx response.
collect
collect(
job_id: str,
*,
show_progress: bool = False,
initial_delay: float = 2.0,
poll_interval: float = 2.0,
max_interval: float = 10.0,
) -> IngestResultPoll a previously submitted job until it reaches a final state, with adaptive backoff between initial_delay and max_interval seconds. Raises JobWaitError (carrying job_id) if the wait fails while the job keeps running; call collect(err.job_id) again to resume.
Ingest does not produce a downloadable archive. Use IngestResult.doc_id to search and manage the indexed document.
IngestResult fields: job_id, status, code, doc_id, deduplicated, replaced_doc_ids, evicted_doc_ids, usage, raw. The indexing fields (doc_id, deduplicated, replaced_doc_ids, evicted_doc_ids) are None when the server reported no indexing outcome — None means "no information", never "not deduplicated". On a deduplicated ingest, doc_id is the pre-existing document's id.
ingest
ingest(
file_path: str | os.PathLike[str] | None = None,
*,
remote_url: str | None = None,
base_url: str | None = None,
completion: str | None = None,
attributes: dict[str, Any] | None = None,
attribute_schema: dict[str, Any] | None = None,
show_progress: bool = False,
initial_delay: float = 2.0,
poll_interval: float = 2.0,
max_interval: float = 10.0,
) -> IngestResultCombined submit + collect — submit a document and wait for indexing to finish in one call.
Search methods
search
search(
query: str,
*,
doc_filter: str | None = None,
exclude_doc_ids: list[str] | None = None,
return_assets: bool | None = None,
min_relevance: float | None = None,
target_tokens: int | None = None,
max_tokens: int | None = None,
attribute_filters: list[dict[str, Any]] | None = None,
) -> SearchContextHybrid search across every document in the project namespace. Returns a SearchContext whose .context field is a prompt-ready XML + Markdown block.
| Parameter | Effect |
|---|---|
doc_filter | Restrict to one document by doc_id. For per-doc Q&A, prefer search_in_doc(...). |
exclude_doc_ids | Drop specific docs from the candidate set (e.g. recently superseded versions). |
return_assets | Return the cited documents' figures (and tables, where available) in the response assets field, keyed by doc_id. Images are base64 data URIs referenced as [IMAGE: name] in context. |
min_relevance | Relevance floor, 0–1 (default 0.3). Higher = stricter; lower-relevance hits are dropped before token budgeting. |
target_tokens | Soft token budget — the typical answer size (default 5000). The knob to size a response. Can never exceed max_tokens (clamped down if it would). |
max_tokens | Hard ceiling (default 15000); only matters for tight multi-document clusters. Set it below target_tokens and the soft target is clamped down to match — the hard ceiling always wins. |
attribute_filters | List of filters on document attributes, each {"attr": ..., "op": ..., "value": ...}, e.g. {"attr": "source", "op": "eq", "value": "treasury"}. |
query must be a non-empty string, otherwise ValueError. The client does not expose a retrieval-tier parameter.
SearchContext fields: context, assets, query, namespace, result_count, tokens_estimated, results_dropped, detected_lang, mode, search_units.
search_in_doc
search_in_doc(
query: str,
doc_filter: str,
*,
exclude_doc_ids: list[str] | None = None,
return_assets: bool | None = None,
min_relevance: float | None = None,
target_tokens: int | None = None,
max_tokens: int | None = None,
attribute_filters: list[dict[str, Any]] | None = None,
) -> SearchContextSearch scoped to one document. doc_filter is required here. Use for in-document chatbots, per-document summarization, and section-level retrieval.
Document methods
list_docs
list_docs() -> list[DocInfo]Return every document currently indexed in the project namespace, following pagination. Emits a RuntimeWarning if the server reports a degraded page (documents it could not fetch transiently were skipped). Each DocInfo carries doc_id, title, language, filename, canonical_url, pages, chunkset_count, chunk_count, image_count, table_count, ingested_at, source_job_id, bm25_state, attributes and attribute_schema.
list_attributes
list_attributes() -> AttributeListList the project's typed attributes. AttributeList carries attributes (a list of AttributeInfo(name, type)), max_names (the cap on distinct names) and note (server guidance). A 503 is raised as ApiError with status_code == 503 — retryable, and never to be read as "no attributes".
get_doc
get_doc(doc_id: str) -> DocInfoLook up one document by doc_id. Raises ValueError on empty input; a 404 from the server surfaces as ApiError.
delete_doc
delete_doc(doc_id: str) -> DeleteDocResponseRemove a document from the project namespace. The response reports vectors_deleted (index rows removed) and storage_deleted (whether the stored payload was also removed) so you can verify the cleanup landed.
Lifecycle
close
close() -> NoneClose the underlying httpx.Client. Also called automatically when used as a context manager:
with Index4AI() as client:
client.ingest("doc.pdf")
# client closed on exitExceptions
All exceptions import from index4ai and derive from Index4AIError.
| Exception | Raised when |
|---|---|
InvalidApiKeyError | Missing / wrong-prefix API key — raised at construction, before any HTTP. Subclass of InvalidInputError. |
InvalidInputError | Invalid or missing input to an SDK method. |
ApiError | Server returned a non-2xx response. Carries status_code, response_body, and (where relevant) job_id and file_path. |
InvalidResponseError | Server response was unparseable or missing a required field (e.g. job_id from submit). |
JobWaitError | Waiting for a submitted job failed (network, unreadable status) while the job keeps running. Carries job_id; resume with collect(err.job_id). |
SubmitUncertainError | The connection failed while a submit was in flight; a job may already exist. Carries source; check list_docs() before re-submitting. |
See also
- index4.ai in the SDK — workflow walkthrough.
AsyncIndex4AI— async counterpart.- index4.ai for developers — endpoint-level reference, RetrievalContext format, billing.