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 with | Main Mahvash features |
|---|---|---|
| Help support agents answer tickets faster and more consistently | Ticketing support copilot | Retrieval with citations, moderation, idempotent drafts |
| Let customers ask questions about their own documents | Customer document portal | Vector stores, file_search, citations |
| Turn phone calls into transcripts and follow-ups | Voice support desk | Transcription, responses, speech |
| Analyze or label a large backlog overnight | Process a ticket backlog | Batches, structured JSON output |
| Add AI to a product used by many customers | Multi-customer SaaS integration | Projects, pinned API keys, per-customer limits |
| Offer a live chat assistant on your site or app | Interactive support chat | Streaming, 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"