Skip to content

Guides

Multi-customer SaaS integration

Give each of your customers a clear project boundary in Mahvash, while your backend stays the only place that decides which credential a request uses.

How the pieces connect

  1. 01Authenticated customer
  2. 02Tenant mapping
  3. 03Pinned project key
  4. 04Customer result

A real-world example

Take Daftar, an online accounting product used by thousands of small businesses. Daftar wants to add an Ask your books assistant, so an owner can ask "Which supplier did we pay the most last quarter?" and get an answer from their own reports.

The hard requirement: a bakery must never see a tile shop's numbers. Daftar solves it by giving every customer business its own Mahvash project, with its own API key and its own document store. Daftar's backend maps each signed-in user to the right project before every call.

What Daftar gets

  • Isolation enforced twice. Daftar checks the customer, and Mahvash refuses anything outside that customer's project.
  • Per-customer usage that can be used for pricing plans or fair-use limits.
  • Safe offboarding. Revoking a customer's key and deleting its project data removes that customer cleanly.
  • Limits per customer, so one very active customer cannot slow down the others.

See it with one customer

StepWhat happensIn this example
1. Sign-upA new business joins Daftar; a provisioning job creates its Mahvash project and API key.Rose Bakery → its own project and a key stored in Daftar's secret manager.
2. DataThe business's monthly reports are indexed in its own vector store.Only Rose Bakery's files are in that store.
3. QuestionThe owner asks the assistant a question.“Which supplier did we pay the most last quarter?”
4. RoutingDaftar maps the signed-in user to the customer and loads that customer's key.Session → customer 4812 → Rose Bakery's key.
5. AnswerMahvash searches only Rose Bakery's store and answers.Another customer's data is unreachable, even by ID.

Daftar keeps the mapping in its own database and uses it on every request:

-- Your database, not Mahvash
customer_id | name          | mahvash_project | credential_ref              | vector_store
------------+---------------+-----------------+-----------------------------+----------------
4812        | Rose Bakery   | <project-uuid-a> | secret://mahvash/cust-4812  | vs_<store-a>
4813        | Tehran Tiles  | <project-uuid-b> | secret://mahvash/cust-4813  | vs_<store-b>

Even if a store ID belonging to another customer reached this code by mistake, Mahvash would answer 404, because that store is not in the project the key is pinned to.

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.

Map customer identity to a project

Your SaaS authenticates its own customers; Mahvash does not know them. Bridge the two with an explicit mapping in your database:

  • your customer ID → a Mahvash project ID;
  • your customer ID → a reference to that project's API key in your secret store.

With one project per customer, each customer's responses, files and stores are isolated by Mahvash itself, in addition to your own checks.

Important:Never accept a project ID from the browser as authorization. The browser tells you who the user is (through your own session); your database tells you which project they map to.

Provision a customer project

When a customer signs up, a provisioning job running with an administrator's user JWT:

  1. 1Creates a project for the customer.
  2. 2Issues a project API key, ideally with limited scopes and a per-key requests_per_minute, and stores the token in your secret manager — it is shown only once.
  3. 3Creates the customer's own files and vector stores if they need a private search corpus.
  4. 4Records the project ID and key reference against the customer.

Route each request

For every user request:

  1. 1Authenticate the user and resolve their customer in your own database.
  2. 2Load that customer's project key from the secret store.
  3. 3Call /v1/responses with that key. The key is pinned to its project, so there is no header to get wrong.

Do not add a caller-supplied X-Mahvash-Project: a pinned key refuses a conflicting selector anyway, and the mapping should come only from your server.

API actions in this step

Server-side tenant routing

The example takes an authenticated customer ID, looks up its server-owned project configuration and calls Responses. The customer receives only the result; no Mahvash key or cross-customer ID ever reaches the browser.

Implementation example

// Resolve the signed-in tenant in your app; never take a key from the browser.
const tenant = await db.tenants.getForSession(session);
const projectKey = await secrets.get(tenant.mahvashCredentialRef);
const response = await fetch("https://api.mahvashai.ir/v1/responses", {
  method: "POST",
  headers: { Authorization: "Bearer " + projectKey, "Content-Type": "application/json" },
  body: JSON.stringify({ model: "auto", input: userMessage })
});
if (!response.ok) throw new Error("Mahvash request failed: " + response.status);
const body = await response.json();
await db.tenantRuns.insert({ tenantId: tenant.id, responseId: body.id });
return body.output;

Example response checkpoint

{
  "id": "resp_example",
  "object": "response",
  "status": "completed",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "Here is your answer..."
        }
      ]
    }
  ]
}

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

Tenant-aware records

Store Mahvash response IDs, file IDs and store IDs next to the owning customer and project in your database. Use that mapping to filter history, render citations and run cleanup when a customer leaves.

Per-project usage also gives you a clean basis for billing each customer for their consumption.

API actions in this step

Isolation failures

Stop the request — do not improvise — when the customer has no mapping, the key has been revoked, or an ID does not belong to that customer's project. Never fall back to another customer's project or to a shared global key.

Use the same pattern for

  • CRM and sales tools — an assistant over each company's own deals and notes.
  • HR platforms — policy and payroll questions per employer.
  • E-learning platforms — a tutor per school, using that school's own materials.
  • Agencies — one project per client, so client material never mixes.
  • Marketplaces — assistants for each seller over their own catalog and orders.