index4.ai Quickstart
From a blank project to prompt-ready context in three steps — ingest → wait → search — plus a fourth showing how to drop the result into an LLM call.
You need a project API key (prefix poma_proj_gr_…) — create one in the console.
Every endpoint and field is in the API reference.
Direct API usage
The three steps with raw curl. Full request/response shapes and every option are in the API reference.
export API="https://api.index4.ai/v1"
export INDEX4AI_API_KEY="poma_proj_gr_…"1. Ingest a document
Raw bytes (application/octet-stream); the filename rides in Content-Disposition — required, it's how the server infers the file type.
JOB=$(curl -sS -X POST "$API/ingest" \
-H "authorization: Bearer $INDEX4AI_API_KEY" \
-H "content-type: application/octet-stream" \
-H 'content-disposition: attachment; filename="annual-report.pdf"' \
--data-binary @annual-report.pdf)
JOB_ID=$(echo "$JOB" | jq -r .job_id) # response is a job object — grab its id2. Wait for the job to finish
Job lifecycle: pending → processing → indexing → done (or failed). Stream it, or poll it:
curl -N "https://api.index4.ai/status/v1/jobs/$JOB_ID" \
-H "authorization: Bearer $INDEX4AI_API_KEY"while :; do
STATUS=$(curl -sS "$API/jobs/$JOB_ID/status" \
-H "authorization: Bearer $INDEX4AI_API_KEY" | jq -r .status)
echo "status: $STATUS"
case "$STATUS" in
done|failed) break ;;
*) sleep 2 ;;
esac
doneAt done the document is already indexed and searchable — there is no archive to download.
3. Search
curl -sS -X POST "$API/search" \
-H "authorization: Bearer $INDEX4AI_API_KEY" \
-H "content-type: application/json" \
-d '{
"query": "How did operating margin change year over year?"
}' | jq -r .contextYou get back a RetrievalContext — a single string field of XML + Markdown, ready to paste into an LLM prompt:
<context>
<doc id="annual-report" title="Annual Report 2025" pages="42">
[p42]
## Operating margin
Operating margin rose from **18.4%** in FY24 to **21.1%** in FY25, …
[…]
Cost-of-goods-sold improvements contributed roughly 1.6 pts …
</doc>
</context>It's already sandwich-ordered, skip-marked ([…] / [pN]), token-budgeted, and citation-ready (id / title / pages on <doc>). See RetrievalContext format for the grammar.
4. Use the context with an LLM
The context field is a single string — feed it straight to any model:
import os, requests, openai
ctx = requests.post(
"https://api.index4.ai/v1/search",
headers={"Authorization": f"Bearer {os.environ['INDEX4AI_API_KEY']}"},
json={"query": "How did operating margin change year over year?"},
timeout=30,
).json()["context"]
resp = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Answer using ONLY the context. Cite document ids."},
{"role": "user", "content": ctx},
],
)
print(resp.choices[0].message.content)That's the whole loop: ingest → search → prompt. No vector DB to set up, no reranker to tune, no prompt assembly to hand-write.
With the Python SDK
The index4ai SDK wraps the same loop in a few lines: ingest submits the file and blocks until it is indexed, and search returns the prompt-ready block. It reads the project key from INDEX4AI_API_KEY.
from index4ai import Index4AI
client = Index4AI() # validates the key prefix locally
client.ingest("annual-report.pdf") # submit, then wait until done
ctx = client.search("How did operating margin change year over year?")
print(ctx.context) # XML + Markdown, ready for a promptFull surface: Index4AI reference, AsyncIndex4AI reference, SDK overview.
Next
- Ingestion — file types, typed attributes for filtering (list existing ones with
GET /attributesbefore adding new names; migrating from labels /meta_int_*), async semantics, redoing a doc. - Retrieval —
min_relevance,target_tokensvsmax_tokens, their defaults, and when to override each. - API reference — every endpoint and field.