Create a key, then call these tools from your own application — chat, lesson plans and PowerPoint decks, and call transcription.
A key is shown once, when you create it. We store only a hash, so it cannot be recovered later.
If you have never called an API before, start here. Three steps and you are done.
Use the box above. Give it a name so you remember what it is for, and press Create key. You will see something like:
yg_live_xK9mQ2vB7nR4tL8wY6pZ3jH5sD1fG0aC
Copy it immediately. We store only a scrambled version, so we cannot show it to you again. If you lose it, revoke it and create another — that is normal and costs nothing.
Anyone with this key can use your account. Treat it like a password:
If it leaks, press Revoke here. It stops working instantly.
Open a terminal and paste this, replacing the key with yours:
curl -X POST https://ai.yugam.co/api/v1/chat \
-H "X-API-Key: yg_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"prompt": "Say hello in Hindi"}'
You should get back:
{"reply": "नमस्ते! आप कैसे हैं?", "mode": "balanced"}
That is it. Everything below is detail on top of that.
| Piece | What it is |
|---|---|
| curl | A program for calling APIs. Built into Mac and Linux; on Windows use PowerShell or Git Bash. |
| -X POST | "I am sending you something", as opposed to just asking for a page. |
| -H | A header — extra information attached to the request. Your key goes in one. |
| -d | The data you are sending, written as JSON. |
| X-API-Key | The header we look at to know who you are. Every request needs it. |
Send text, get text back.
The simplest form — one question, one answer:
curl -X POST https://ai.yugam.co/api/v1/chat \
-H "X-API-Key: yg_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"prompt": "Write a note to parents about sports day."}'
Add mode. If you leave it out you get balanced.
| Mode | Speed | Use it for |
|---|---|---|
| fast | ~26 words/sec | Short answers, simple rewrites |
| balanced | ~11 words/sec | Most things. The default. |
| thinking | Slowest | Problems needing step-by-step reasoning |
-d '{"prompt": "Explain photosynthesis to a 10 year old", "mode": "fast"}'
The server remembers nothing between requests. To continue a conversation, send the whole
history each time using messages instead of prompt:
{
"messages": [
{"role": "user", "content": "What is the capital of India?"},
{"role": "assistant", "content": "New Delhi."},
{"role": "user", "content": "What is its population?"}
]
}
role is user for the person and assistant for previous replies.
import requests
r = requests.post(
"https://ai.yugam.co/api/v1/chat",
headers={"X-API-Key": "yg_live_your_key_here"},
json={"prompt": "Summarise this in one line: ..."},
timeout=900,
)
print(r.json()["reply"])
const r = await fetch("https://ai.yugam.co/api/v1/chat", {
method: "POST",
headers: {
"X-API-Key": "yg_live_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt: "Say hello" }),
});
const data = await r.json();
console.log(data.reply);
Answers take time. This runs on our own server, not a giant cloud cluster. A long answer can take several minutes. Set your timeout to at least 900 seconds, or your code will give up before we finish.
Send a topic and a class. Get back a timed lesson plan, and a PowerPoint deck you can project.
The short way — one call, and a .pptx file lands on your disk:
curl -X POST https://ai.yugam.co/api/v1/lessons/pptx \
-H "X-API-Key: yg_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"topic": "Photosynthesis", "grade": "Grade VII", "subject": "Science", "minutes": 40}' \
-o lesson.pptx
The plan is saved too, so you can fetch it again as JSON or re-download the deck later.
| Field | Required | Allowed | Meaning |
|---|---|---|---|
| topic | yes | 2–200 characters | What the lesson is about |
| grade | yes | 1–40 characters | The class, e.g. Grade VII |
| subject | no | up to 80 characters | Helps pitch the language and examples |
| minutes | no | 10–180, default 40 | Length of the period |
| segments | no | 3–8, default 5 | How many parts the lesson is split into |
The same thing, but returns the plan as JSON instead of a file:
{
"id": "df049d3bdd01",
"created_at": "2026-09-04T11:30:45+00:00",
"pptx_url": "/api/v1/lessons/df049d3bdd01/pptx",
"plan": {
"title": "Photosynthesis Lesson Plan",
"summary": "...",
"objectives": ["...", "...", "..."],
"materials": ["...", "...", "..."],
"segments": [
{"title": "Introduction", "minutes": 5,
"points": ["Hello class, today we will learn about photosynthesis.", "..."],
"activity": "Show a diagram of photosynthesis and ask what they notice."}
],
"homework": "Draw a diagram of photosynthesis and write a short paragraph."
}
}
The segment minutes always add up to exactly the minutes you asked
for — we correct the total before saving, so you never get a 40-minute period whose
parts sum to 37.
curl https://ai.yugam.co/api/v1/lessons/df049d3bdd01/pptx \
-H "X-API-Key: yg_live_your_key_here" \
-o lesson.pptx
The deck is a title slide, a plan-at-a-glance slide showing the timing, one slide per segment, and a homework slide. 16:9, in the school's colours.
import requests
KEY = {"X-API-Key": "yg_live_your_key_here"}
# One call, straight to a file
r = requests.post(
"https://ai.yugam.co/api/v1/lessons/pptx",
headers=KEY,
json={"topic": "Fractions", "grade": "Grade V", "subject": "Maths", "minutes": 35},
timeout=1200,
)
r.raise_for_status()
open("fractions.pptx", "wb").write(r.content)
# Or get the plan first, and read it before deciding
plan = requests.post(
"https://ai.yugam.co/api/v1/lessons",
headers=KEY,
json={"topic": "Fractions", "grade": "Grade V", "segments": 6},
timeout=1200,
).json()
for seg in plan["plan"]["segments"]:
print(f"{seg['minutes']:>3} min {seg['title']}")
import { writeFile } from "node:fs/promises";
const r = await fetch("https://ai.yugam.co/api/v1/lessons/pptx", {
method: "POST",
headers: {
"X-API-Key": "yg_live_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({ topic: "The Water Cycle", grade: "Grade VI", minutes: 40 }),
});
if (!r.ok) throw new Error((await r.json()).error.message);
await writeFile("water-cycle.pptx", Buffer.from(await r.arrayBuffer()));
A plan takes several minutes — about 4 to 6 on the current server, and longer if someone else is generating one at the same time, because the server writes one at a time. Set your timeout to at least 1200 seconds. Unlike call recordings, there is no queue to poll: the request stays open until the plan is done.
| Route | What it does |
|---|---|
| GET /api/v1/lessons | Recent plans, newest first. ?limit= up to 100. |
| GET /api/v1/lessons/{id} | One plan in full |
| DELETE /api/v1/lessons/{id} | Delete a plan |
Plans are shared across the team — a listing shows everyone's, with
owner_email saying who generated each one.
Upload audio, get a transcript and a full analysis of the call.
Processing happens in two stages, and you can see both:
| Stage | What happens | Status you will see |
|---|---|---|
| 1. Transcribe | Speech becomes text | transcribing |
| 2. Analyse | Text becomes a structured record | summarising |
| Finished | Everything is ready | done |
Uploading returns immediately with an id. You then poll — ask for the
result every 30 seconds or so until status is done.
curl -X POST https://ai.yugam.co/api/v1/calls \
-H "X-API-Key: yg_live_your_key_here" \
-F "file=@recording.mp3"
-F attaches a file. The @ means "read from this path". The field
must be called file.
{"id": "9174c1d4ac87", "status": "queued", "filename": "recording.mp3"}
Accepted: mp3, wav, m4a, mp4, ogg, opus, aac, amr, flac, webm. Up to 500 MB. A 5-minute call takes a few minutes to process.
Processing is slow on the current server. Recordings are processed one
at a time; a 10-minute call can take an hour or more, and the rest wait their turn as
queued. Poll the call until its status is done.
curl https://ai.yugam.co/api/v1/calls/9174c1d4ac87 \
-H "X-API-Key: yg_live_your_key_here"
import requests, time
H = {"X-API-Key": "yg_live_your_key_here"}
up = requests.post("https://ai.yugam.co/api/v1/calls",
headers=H, files={"file": open("call.mp3", "rb")})
call_id = up.json()["id"]
while True:
r = requests.get(f"https://ai.yugam.co/api/v1/calls/{call_id}", headers=H).json()
if r["status"] in ("done", "failed"):
break
print("still", r["status"], "…")
time.sleep(30)
print(r["transcript"])
print(r["record"]["summary"])
print("Coaching:", r["record"]["coaching_note"])
Three groups: the words, measured delivery, and the analysis.
{
"transcript": "नमस्कार सर, मैं ... से बात कर रही हूँ ...",
"words": 427,
"duration_s": 274.6,
"needs_review": true,
"review_reason": "one word repeats 6 times in a row — part of the audio was not understood"
}
Always check needs_review. When it is true,
the recogniser struggled and the transcript may be unreliable. Show the warning to your
users rather than presenting the result as fact.
metricsCounted from the audio, not judged by a model. Useful for coaching.
| Field | Meaning | What to look for |
|---|---|---|
| loudness_db | Average level | Below −30 is very quiet; accuracy suffers |
| peak_db | Loudest moment | Near 0 means clipping |
| talking_pct | % of the call with speech | Very high can mean nobody paused to listen |
| words_per_min | Speaking pace | Over ~180 is rushed; under ~100 is hesitant |
| pauses | Number of silences over 0.6s | Very few suggests a scripted monologue |
| longest_pause_s | Longest silence | A long gap may be a dropped line |
record{
"record": {
"parent_name": "Ravi",
"child_current_school": "केंद्रीय विद्यालय",
"grade_enquired_for": "not stated",
"locality": "Kalyanpur",
"enquiry_source": "Facebook",
"is_existing_parent": "no",
"fee_discussed": "yes",
"campus_visit_offered": "yes",
"visit_outcome": "vague / no commitment",
"objections": ["no time", "happy with current school"],
"next_step": "call back at 2pm",
"interest_level": "warm",
"call_purpose": "first contact",
"outcome": "information given",
"what_happened": "The counsellor opened by introducing the school ...",
"topics_covered": ["hostel", "sports", "fees"],
"questions_parent_asked": ["What is the annual fee?"],
"counsellor_tone": "warm",
"listened_well": "partly",
"asked_discovery_questions": "yes",
"handled_objections": "partly",
"asked_for_commitment": "no",
"call_quality_score": 3,
"what_went_well": ["Explained the sports programme clearly"],
"what_to_improve": ["Never asked for a specific visit date"],
"coaching_note": "You built rapport well, but the call ended without ..."
}
}
| Field | Possible values |
|---|---|
| interest_level | hot · warm · cold · not stated |
| call_purpose | first contact · follow up · callback scheduling · qualification · visit booking · other |
| outcome | visit booked · callback agreed · information given · no progress · wrong person |
| visit_outcome | date agreed · declined · vague / no commitment · not stated |
| counsellor_tone | warm · neutral · rushed · pushy · unclear |
| listened_well | yes · partly · no |
| handled_objections | yes · partly · no · none raised |
| call_quality_score | 1 to 5 (5 = clear next step agreed and parent felt heard) |
Any text field can be the literal string "not stated". That means the call did
not cover it — it is not an error, and not a guess. Handle it in your code.
Redo only the analysis, keeping the existing transcript. Much faster and cheaper than re-uploading, because transcription is the slow part.
curl -X POST https://ai.yugam.co/api/v1/calls/9174c1d4ac87/reanalyse \
-H "X-API-Key: yg_live_your_key_here"
curl https://ai.yugam.co/api/v1/calls -H "X-API-Key: yg_live_your_key_here"
Every error looks the same and tells you what to do next. There is only ever one shape to handle.
{
"error": {
"code": "invalid_api_key",
"message": "That API key is not valid, or it has been revoked.",
"hint": "Check the key, or create a new one on the Developers page."
}
}
Check error.code in your program; show error.message to a person.
hint is not always present.
| Code | HTTP | What to do |
|---|---|---|
| not_authenticated | 401 | You sent no key. Add the X-API-Key header. |
| invalid_api_key | 401 | Wrong key, or it was revoked. Create a new one above. |
| bad_request | 400 | Something in your JSON is missing or out of range. The message names the field. |
| not_found | 404 | No plan or call with that id. |
| timeout | 504 | Your request took too long. Raise your client timeout to 1200s. |
| processing_paused | 503 | New call recordings are not being accepted on this server. Existing calls can still be read. |
| model_unavailable | 503 | The server is restarting. Wait a minute and retry. |
| generation_failed | 502 | The plan came back unusable. Retry, or rephrase the topic more plainly. |
| too_many_keys | 409 | You have 10 active keys. Revoke one first. |
| file_too_large | 413 | The recording is over 500 MB. Compress or split it. |
| unsupported_file | 415 | Not an audio format we read. See the accepted list above. |
Retry on 502, 503 and 504 — not on 400 or 401. The first three mean the server had a bad moment and the same request may well work next time. The last two mean the request itself is wrong, and sending it again will fail identically.
One generation at a time. The server runs a single model job at once, so if a colleague is generating a lesson plan your request waits behind theirs. That waiting is on top of the request's own time, which on the current server is minutes, not seconds; hence the long timeouts.