Skip to content

Guides

Customer document portal

Let signed-in customers ask questions about documents your application authorizes them to read, with answers that link back to the source.

How the pieces connect

  1. 01Authorized question
  2. 02Portal backend
  3. 03Mahvash file search
  4. 04Cited answer

A real-world example

Take Arman Insurance. Its customers can already download their policy documents from a customer portal, but the documents are long and full of clauses, so many customers still call the contact center to ask a simple question: "Am I covered for this?"

With Mahvash, the portal gets an Ask about your policy box. A signed-in customer types a question and gets a plain-language answer that points to the exact clause in their own policy — never someone else's.

What the business gets

  • Answers in seconds, at any hour, for questions that used to need a phone call.
  • Trustworthy answers. Each answer links to the clause it came from, so customers and staff can check it.
  • Privacy by design. The portal decides which documents a customer may read before Mahvash searches anything.
  • Fewer routine calls, so experts can focus on claims and complex cases.

See it with a real question

StepWhat happensIn this example
1. Customer asksA signed-in customer types a question in the portal.“Does my home policy cover water damage that came from my neighbour's apartment?”
2. Access checkThe portal confirms which documents this customer may read.Only policy HP-20931 and its vector store.
3. RetrievalMahvash searches only that store.Clause 4.2 “Water damage” and clause 7 “Exclusions”.
4. AnswerThe model answers in plain language, with citations.“Yes. Clause 4.2 covers water escaping from a neighbouring property… clause 7 excludes gradual leaks you knew about.”
5. DisplayEach citation opens the right document in the portal's own viewer.A link to page 6 of the customer's policy.

The portal backend sends this request after its own access check, and receives the answer with its citation:

// Runs only after the portal confirmed this customer owns policy HP-20931.
const response = await fetch("https://api.mahvashai.ir/v1/responses", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.MAHVASH_PROJECT_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "auto",
    input: "Does my home policy cover water damage that came from my neighbour's apartment?",
    tools: [{ type: "file_search", vector_store_ids: [policy.vectorStoreId] }],
    include: ["file_search_call.results"],
  }),
});

The only store searched is the one belonging to policy HP-20931. If the customer changed a store ID in the browser, the portal would not use it: the store is chosen on the server from the customer's own records.

Note:The company, customer and policy details in this example are fictional. Mahvash answers from the documents and data you provide; it does not invent your policies.

Keep access in your application

Your portal decides which user can open which document. Mahvash projects and vector stores scope retrieval, but they do not know your users — they cannot replace your application's authorization.

So the portal backend always does two things in order: it checks the user's access in its own database, and only then chooses which store Mahvash may search.

Upload and index documents

  • Upload each allowed document with /v1/files, attach it to a vector store, and wait until the vector store file is completed.
  • Save the returned file-... and vs_... IDs on your own document record.
  • Design stores around access boundaries. Documents that the same set of users may read can share a store; customers who must never see each other's content need separate stores, or separate projects.

Answer one authorized question

  1. 1Authenticate the portal user and load the documents they may read.
  2. 2Map those documents to the stores that contain them. If there is none, stop.
  3. 3Send a Responses request with file_search limited to the authorized store IDs.
  4. 4Add include: ["file_search_call.results"] when your interface shows the retrieved passages.
  5. 5Read file_citation annotations rather than trying to parse filenames from the answer text.

API actions in this step

Backend query implementation

The example accepts a store ID only after your access check succeeds, and returns the answer text and citation metadata to the portal.

Important:The browser must never supply a trusted project or store ID. Treat any ID coming from the client as a lookup key into your own records, never as permission.

Implementation example

// The portal authorizes document access before this server call.
const permitted = await db.permissions.canRead(userId, documentId);
if (!permitted) throw new Error("Forbidden");
const storeId = await db.documents.vectorStoreId(documentId);
const response = await fetch("https://api.mahvashai.ir/v1/responses", {
  method: "POST",
  headers: { Authorization: "Bearer " + process.env.MAHVASH_PROJECT_KEY!, "Content-Type": "application/json" },
  body: JSON.stringify({ model: "auto", input: "Answer from the document and cite the source: " + question,
    tools: [{ type: "file_search", vector_store_ids: [storeId] }],
    include: ["file_search_call.results"] })
}).then(r => r.json());
return { answer: response.output, responseId: response.id };

Example response checkpoint

{
  "id": "resp_example",
  "status": "completed",
  "output": [
    {
      "type": "message",
      "content": [
        {
          "type": "output_text",
          "text": "The agreement renews annually...",
          "annotations": [
            {
              "type": "file_citation",
              "file_id": "file-<uuid>"
            }
          ]
        }
      ]
    }
  ]
}

Illustrative response excerpt. Your application owns the surrounding workflow and customer data.

Render a source-aware answer

Show each citation as a link to your own document viewer, which enforces your own permissions. Keep a mapping from Mahvash file-... IDs to your document records; do not expose raw download URLs that bypass the portal.

API actions in this step

No result or revoked access

  • Nothing indexed yet: show a waiting state instead of an empty answer.
  • Access revoked: stop querying on the user's behalf immediately and remove your links to the document.
  • No citation: present the answer as unsupported, not as sourced.

Use the same pattern for

  • Insurance — policy wording, coverage limits and claim procedures.
  • Legal and real estate — questions about a client's own contracts and leases.
  • HR — employee handbooks and benefits, visible only to staff.
  • Education — regulations and course guides per faculty or program.
  • Manufacturers and B2B suppliers — manuals, certificates and specifications per customer account.