Skip to content

Guides

Integration examples

Proven patterns for calling Mahvash from your own application, plus complete scenarios that combine several API calls with the authorization, storage and review steps real products need.

Choose a real workflow

Each scenario below describes a complete product feature: where Mahvash fits, what you prepare once, what happens on every request, a server-side implementation, and how to handle failure. Every scenario opens with a realistic business example and walks through one real request from start to finish.

If you want to…Start withMain Mahvash features
Help support agents answer tickets faster and more consistentlyTicketing support copilotRetrieval with citations, moderation, idempotent drafts
Let customers ask questions about their own documentsCustomer document portalVector stores, file_search, citations
Turn phone calls into transcripts and follow-upsVoice support deskTranscription, responses, speech
Analyze or label a large backlog overnightProcess a ticket backlogBatches, structured JSON output
Add AI to a product used by many customersMulti-customer SaaS integrationProjects, pinned API keys, per-customer limits
Offer a live chat assistant on your site or appInteractive support chatStreaming, conversation state, file attachments

Start with the one closest to your product, then use the linked API actions for exact fields.

Server-side application

The foundation of every integration: your browser or mobile app talks to your backend, and your backend talks to Mahvash.

  • Authenticate your own user and decide whether they may use the feature.
  • Build the prompt on the server from trusted data plus the user's input; do not accept a full prompt, model or project from the browser unchecked.
  • Call Mahvash with the project key, an idempotency key and a timeout.
  • Return a controlled result — text, a status, your own IDs — not the raw Mahvash response.
// Run on your server. Never send the project key to the browser.
export async function answerQuestion(question) {
  const response = await fetch("https://api.mahvashai.ir/v1/responses", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + process.env.MAHVASH_API_KEY,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({ model: "auto", input: question }),
  });
  if (!response.ok) throw new Error("Mahvash HTTP " + response.status);
  const result = await response.json();
  return { id: result.id, output: result.output };
}

OpenAI SDK-compatible client

If you already use an OpenAI SDK, change two settings: the base URL (https://api.mahvashai.ir/v1) and the key (a Mahvash project key). Supported /v1 operations then work unchanged. Use direct HTTP for /api/v1 workspace endpoints.

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.MAHVASH_API_KEY,
  baseURL: "https://api.mahvashai.ir/v1",
});

const response = await client.responses.create({
  model: "auto",
  input: "Say hello in one sentence.",
});
console.log(response.output_text);

Reusable file across requests

When users refer to the same file over several turns — a contract in a chat, a brief in a drafting tool — upload it once as a project asset, save its UUID with your conversation, and pass it in asset_ids whenever it is needed. Asset IDs are project-scoped: never reuse one across unrelated projects or customers.

curl https://api.mahvashai.ir/api/v1/chat/assets/upload \
  -H "Authorization: Bearer $MAHVASH_API_KEY" \
  -F 'file=@./brief.pdf'

# Keep the returned asset UUID in ASSET_ID, then use it in a supported request:
curl https://api.mahvashai.ir/v1/responses \
  -H "Authorization: Bearer $MAHVASH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","input":"Summarize this file","asset_ids":["<asset-uuid>"]}'

Streaming UI

Request stream: true, read events incrementally, append response.output_text.delta to the visible answer, and finish on response.completed, response.incomplete or response.failed. A disconnected stream is not proof of failure: keep the response ID from response.created and retrieve the result.

const response = await fetch("https://api.mahvashai.ir/v1/responses", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.MAHVASH_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ model: "auto", input: "Say hello", stream: true }),
});
if (!response.ok || !response.body) throw new Error("HTTP " + response.status);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let pending = "";
let terminal = false;
while (!terminal) {
  const { value, done } = await reader.read();
  if (done) break;
  pending += decoder.decode(value, { stream: true });
  const frames = pending.split(/\r?\n\r?\n/);
  pending = frames.pop() ?? "";
  for (const frame of frames) {
    const data = frame.split(/\r?\n/).filter(line => line.startsWith("data:"))
      .map(line => line.slice(5).trim()).join("\n");
    if (!data || data === "[DONE]") continue;
    const event = JSON.parse(data);
    if (event.type === "response.output_text.delta") process.stdout.write(event.delta);
    if (["response.completed", "response.incomplete", "response.failed"].includes(event.type)) terminal = true;
  }
}
if (!terminal) throw new Error("Stream disconnected; inspect the response before retrying.");

Background worker and webhooks

For work nobody waits on, submit with background: true, store the response ID in your job table, and complete the job when polling or a verified webhook reports a terminal status. Deduplicate webhook event IDs before updating your own state.

curl https://api.mahvashai.ir/v1/responses \
  -H "Authorization: Bearer $MAHVASH_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: <unique-job-id>" \
  -d '{"model":"auto","input":"Summarize this document","background":true}'

# Save the returned response ID, then retrieve its current status:
curl https://api.mahvashai.ir/v1/responses/<response-id> \
  -H "Authorization: Bearer $MAHVASH_API_KEY"