Guides
Build document Q&A
An end-to-end walkthrough: prepare a project, upload a document, index it, connect it to the project, ask a question, read the citations, and clean up.
What you will build
At the end of this guide, your server can answer a question such as "How many vacation days do new employees get?" from your own handbook, and show which file the answer came from. The flow is:
- 1A user JWT prepares a project and a project API key (once).
- 2Your server uploads documents and indexes them in a vector store.
- 3For each question, your server calls Responses with the project key, and Mahvash retrieves relevant passages and answers with citations.
Each step below links to the exact API actions and shows a request and an illustrative response.
1. Prepare the project
Create (or choose) a project for this knowledge base using a user JWT, then issue a project API key for your server. Keeping documents in their own project means their files, stores and key cannot be mixed up with other workloads.
Store the key in your secret manager. Every following call uses it, and everything it creates belongs to this project.
curl -X POST 'https://api.mahvashai.ir/api/v1/tenancy/projects' \
-H "Authorization: Bearer $MAHVASH_USER_JWT" \
-H "Content-Type: application/json" \
-d '{
"name": "Research",
"slug": "research"
}'{
"status": 201,
"data": {
"id": "<project-uuid>",
"organization": "<organization-uuid>",
"name": "Research",
"slug": "research"
}
}Illustrative response shape; actual fields depend on the operation and model.
2. Upload a source file
Upload each document with POST /v1/files as multipart/form-data and keep the returned file-... ID in your own database next to your document record.
- Use
purpose=user_datafor documents you want to search. - For large files, use a resumable upload session instead; it produces the same kind of file object.
- Do not send files as base64 JSON.
curl -X POST 'https://api.mahvashai.ir/v1/files' \
-H "Authorization: Bearer $MAHVASH_API_KEY" \
-F 'file=@./your-file'{
"id": "<id>",
"object": "file",
"bytes": 0,
"created_at": 1750000000,
"expires_at": null,
"filename": "example",
"purpose": "user_data",
"status": "processed",
"status_details": null
}Illustrative response shape; actual fields depend on the operation and model.
3. Index it
Create a vector store in the same project and attach the file to it. Attaching starts indexing; poll the vector store file until its status is completed.
failedmeans the document could not be processed — checklast_error, fix the source and try again.- A store can hold many files. Group documents that should be searched together, and use separate stores when different users may read different documents.
Important:A store without any completed file cannot answer questions. Do not open your feature to users until indexing has finished.
curl -X POST 'https://api.mahvashai.ir/v1/vector_stores' \
-H "Authorization: Bearer $MAHVASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Product manuals"
}'{
"id": "<id>",
"object": "vector_store",
"created_at": 1750000000,
"name": "example",
"usage_bytes": 0,
"file_counts": {
"in_progress": 0,
"completed": 0,
"cancelled": 0,
"failed": 0,
"total": 0
},
"status": "completed",
"expires_after": null,
"expires_at": null,
"metadata": {},
"retrieval_placement": "<value>",
"effective_retrieval_placement": null
}Illustrative response shape; actual fields depend on the operation and model.
4. Connect the store to the project (optional)
You have two options for using the store:
- Explicit search: name the store in each request's
file_searchtool (step 5). Best when different users may search different stores. - Project data source: attach the store to the project. With project auto-search enabled, every request that does not set its own tools searches the project's data sources automatically. Best when everyone using the project may search the same knowledge.
Attaching a data source is different from attaching a file to a store: it does not upload or index anything. Requests can still opt out with tools: [] or tool_choice: "none".
curl -X POST 'https://api.mahvashai.ir/api/v1/tenancy/projects/<project_id>/data-sources' \
-H "Authorization: Bearer $MAHVASH_USER_JWT" \
-H "Content-Type: application/json" \
-d '{
"vector_store_id": "3f5a8c4e-6b8d-4a4f-9d2c-1f0a2b3c4d5e"
}'{
"status": 201,
"data": {
"id": "<data-source-uuid>",
"vector_store_id": "<store-uuid>",
"position": 0,
"added_by": "<user-id>"
}
}Illustrative response shape; actual fields depend on the operation and model.
5. Ask and inspect the answer
Send a Responses request with the project key. The request and illustrative response at the end of this step use an explicit file_search tool.
The response contains a file_search_call item followed by the assistant message. Citations are annotations on the output_text, not text inside the answer:
file_citationannotations carry the Mahvashfile_idandfilenamethe passage came from.- Map
file_idto your own document record and render a link to your own viewer, protected by your own permissions. - If the answer has no citation, show it as unsupported rather than presenting it as sourced.
curl https://api.mahvashai.ir/v1/responses \
-H "Authorization: Bearer $MAHVASH_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: <unique-question-id>" \
-d '{
"model": "auto",
"input": "What does the uploaded policy say about retention?",
"tools": [{"type": "file_search", "vector_store_ids": ["vs_<store-uuid>"]}]
}'{
"id": "resp_example",
"object": "response",
"status": "completed",
"output": [
{"type": "file_search_call", "status": "completed"},
{"type": "message", "role": "assistant", "content": [{
"type": "output_text",
"text": "The policy retains records for the stated period.",
"annotations": [{"type": "file_citation", "file_id": "file-<uuid>", "filename": "policy.pdf"}]
}]}
]
}Illustrative response shape; actual fields depend on the operation and model.
6. Manage the lifecycle
Documents change, so plan how they leave the system as carefully as how they enter it:
- Replace a document: upload the new version, attach it to the store, wait for
completed, then remove the old file from the store. - Stop project-wide retrieval: detach the data source. Existing responses keep their citations.
- Remove content: removing a file from a store deletes its index entries but keeps the file; delete the file separately, then delete the store when it is empty.
curl -X DELETE 'https://api.mahvashai.ir/api/v1/tenancy/projects/<project_id>/data-sources/<vector_store_id>' \
-H "Authorization: Bearer $MAHVASH_USER_JWT"