Naadham Developer Documentation
Everything in the Command Center is also a REST API — embed an AI front desk (calls, bookings, omnichannel follow-up) into any product, and receive signed webhooks for calls and bookings. New to Naadham? Start with the Clinic Guide.
Developer API Clinic admin
What it is. Everything in the dashboard is also a REST API, so you can wire Naadham into your own product or back-office. Authenticate with your API key as a bearer token.
Authentication & testing your key
# Your key is in the Authorization header on every request
export NAADHAM_KEY=naadham_sk_xxxxxxxx
# Quick test — who am I? (200 = key works; 401 = bad/rotated key)
curl -i https://naadham.ai/v1/whoami -H "Authorization: Bearer $NAADHAM_KEY"
# → 200 { "tenant_id":"t_ab12…" }
429 with a Retry-After header if you exceed the limit.Common endpoints
| Method | Path | Does |
|---|---|---|
| POST | /v1/auth/signup · /v1/auth/login | create account / sign in |
| PUT | /v1/agent/form | configure the AI |
| GET | /v1/calls · /v1/bookings · /v1/contacts | read your data |
| GET | /v1/usage/summary · /v1/analytics | minutes & analytics |
| PUT | /v1/inventory | upload what you have to sell |
| GET | /v1/inventory/gaps | what callers asked for and you didn't have |
| GET | /v1/summary/monthly | what the assistant did last month |
| POST | /v1/subscription/order | start a plan payment |
Full reference with request/response shapes: API reference below →
Webhooks & EHR Clinic admin
What it is. Naadham pushes events to your server in real time — call.completed and booking.created — each HMAC-signed so you can verify it's genuinely from Naadham. Bookings are also available as FHIR R4 Appointment resources to drop straight into an EHR.
Verifying a webhook
# Each delivery includes X-Naadham-Signature: hex(HMAC_SHA256(raw_body, your_webhook_secret))
import hmac, hashlib
def verify(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
2xx quickly — Naadham retries failed deliveries. Full payloads and the FHIR mapping are below.Authentication (reference)
Requests use a bearer token. Two kinds are accepted, both via the same header:
- API key (
naadham_sk_…) — server-to-server. Issued once at sign-up; store it securely, server-side only. - Session token (
naadham_sess_…) — issued by email+password login, used by the dashboard. Expires after 30 days.
Authorization: Bearer naadham_sk_xxxxxxxxxxxxxxxx
Sign up / log in
curl -X POST https://naadham.ai/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"a-strong-password","org_name":"City Clinic"}'
# → { "tenant_id":"t_ab12…", "session_token":"naadham_sess_…", "api_key":"naadham_sk_…", "trial_minutes":15 }
curl -X POST https://naadham.ai/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"a-strong-password"}'
# → { "tenant_id":"t_ab12…", "session_token":"naadham_sess_…" }
Configure the agent PUT /v1/agent/form
Set the agent's persona and knowledge — the same form the console uses. FAQ answers seed the agent's knowledge base (RAG).
curl -X PUT https://naadham.ai/v1/agent/form \
-H "Authorization: Bearer $NAADHAM_KEY" -H "Content-Type: application/json" \
-d '{
"agent_name":"City Clinic Front Desk",
"greeting":"Hi, City Clinic — how can I help?",
"tone":"friendly",
"default_language":"English",
"languages":["English","Hindi","Tamil","Telugu","Kannada"],
"working_hours":"Mon–Sat 9am–6pm",
"bookable_services":["General Consultation","Dental","Lab Test"],
"transfer_number":"+91...",
"faqs":[{"question":"Do you accept insurance?","answer":"Yes, most major insurers."}]
}'
Channels & web chat
What it is. One agent, every channel. Configure WhatsApp, SMS, web chat and email — and the human-handoff target — with a single endpoint. Inbound messages run your tenant's own agent and land in Inquiries.
GET/v1/channels — current config + your webhook URLs, WhatsApp verify token, email inbound address, and the web-chat embed snippet.
PUT/v1/channels — connect/update any channel. Send only the keys you're changing; the rest are preserved.
curl -X PUT https://naadham.ai/v1/channels \
-H "Authorization: Bearer $NAADHAM_KEY" -H "Content-Type: application/json" \
-d '{
"whatsapp":{"phone_number_id":"1009xxxxxxxxxxxxx"},
"sms":{"provider":"msg91","sender_id":"NAADHM","number":"+91..."},
"email":{"forward_confirmed":true},
"handoff":{"email":"[email protected]","phone":"+91-80-4000-0000"}
}'
# → { "ok": true, "channels": { … } }
Embeddable web chat POST /v1/embed/chat
Put the same AI on your website. Drop in the widget.js snippet from GET /v1/channels, or call the endpoint directly with your public web-chat key (safe to expose in a browser — it's scoped to chat only).
curl -X POST https://naadham.ai/v1/embed/chat \
-H "Content-Type: application/json" \
-d '{"tenant_id":"t_ab12…","key":"wc_your_public_key",
"conversation_id":"c1","body":"What are your hours?"}'
# → { "reply":"We're open Mon–Sat, 9am–6pm.", "transferred":false, "booking_id":null }
Inquiries & human handoff
What it is. A unified feed of every patient conversation across all channels, plus the hand-off signal. When the AI hands off (a patient asks for a person, or asks anything clinical), the inquiry is flagged needs_human and your handoff email/phone is notified. On voice, the live call is transferred to your transfer_number.
GET/v1/inquiries?channel=voice|webchat|whatsapp|sms|email — omit channel for everything.
curl "https://naadham.ai/v1/inquiries?channel=whatsapp" -H "Authorization: Bearer $NAADHAM_KEY"
# → {
# "inquiries": [
# { "channel":"whatsapp", "who":"+9198…", "outcome":"transfer",
# "needs_human": true, "transcript":"You: …\nAI: …", "qa": {} }
# ],
# "needs_human": 1 // count waiting on a human right now
# }
PUT /v1/channels (handoff.email / handoff.phone) and the voice transfer target with transfer_number on PUT /v1/agent/form.Inbound webhooks (WhatsApp / SMS / email)
What it is. Where the providers deliver inbound messages. Naadham resolves the destination number/address to your clinic, runs your agent, persists the inquiry, and replies on the same channel. Paste these URLs into each provider (they're also shown in GET /v1/channels).
| Channel | URL to configure in the provider | Routed by |
|---|---|---|
| WhatsApp (Meta Cloud) | https://api.naadham.ai/webhooks/whatsapp | your phone_number_id |
WhatsApp uses the Meta verification handshake (GET with your verify token) and an X-Hub-Signature-256 check. Email accepts a standard inbound-parse JSON/form payload (to, from, subject, text). Unrecognized numbers/addresses are safely ignored, never misrouted.
Catalogue & unmet demand
The assistant answers "do you have…" from a catalogue you upload — properties, rooms, tables, packages, courses. Slot booking already covers whatever you sell by the hour; this covers whatever a caller filters on.
PUT/v1/inventory — replace the catalogue. Body: {"rows":[{"kind":"property","name":"Alpha 3BHK","bhk":3,"budget":"1.2 crore","area":"Whitefield","available":"yes"}]}. kind and name are columns; every other column becomes a filter, so adding one to your sheet is all it takes for the assistant to answer on it. This is a REPLACE, not a merge — anything missing from the upload has been sold.
GET/v1/inventory — the current catalogue, plus freshness (how old it is, and whether the assistant is quoting from a sheet nobody has touched) and starter_columns for your trade.
PATCH/v1/inventory/item — mark one thing sold or back: {"name":"Prestige 3BHK","available":false}. Re-uploading the whole sheet to strike a single row is the friction that gets dropped, and a stale catalogue is worse than none.
Your columns are the words your callers use. A hotel that writes occupancy is understood when a caller says "for four people"; one that invents sleeps is not. Each trade starts with a suggested set — real estate bhk, budget, area, facing, floor, status; hotels room_type, occupancy, rate, view; restaurants seats, area, time; clinics package, price, prep, duration; courses course, batch_time, fee, seats_left. Common phrasings map automatically, and anything the catalogue does not record is said out loud on the call rather than quietly ignored.
GET/v1/inventory/gaps?days=30 — what callers asked for that you did not have, commonest first, counting distinct callers rather than repeat calls. Every other demand signal is inferred from clicks; this is a person saying it out loud on the phone. Response: {"gaps":[{"kind":"property","asked_for":"bhk 2, budget 80 lakh","callers":31,"requests":44}],"headline":"…"}
GET/v1/inventory/callbacks?days=90 — people whose unmet request your current catalogue would now answer, newest ask first, one per caller. Opt-outs are removed before you see them. This suggests and never dials: you turn the list into a normal outreach campaign, which is where consent is attested and where the calling window already applies. Response: {"suggestions":[{"caller":"+91…","asked_for":"bhk 3, budget 1.2 crore","now_available":["Prestige 3BHK"],"message":"You asked about…"}]}
POST/v1/inventory/callbacks/dismiss — mark people handled: {"callers":["+91…"]}. Without it the same person is suggested every week.
GET/v1/summary/monthly?month=2026-08 — calls answered, bookings taken, conversations handled and average quality score, each with the previous month beside it. Defaults to the month just gone.
Usage & billing
GET/v1/usage/summary — minutes consumed, minutes left, conversations.
GET/v1/subscription — your current plan, term and the monthly/yearly price of each tier.
POST/v1/subscription/order — start a plan payment (returns a payment session for checkout); confirm with /v1/subscription/confirm. The legacy /v1/recharge/* endpoints are deprecated.
curl https://naadham.ai/v1/usage/summary -H "Authorization: Bearer $NAADHAM_KEY"
# → { "minutes_consumed": 320, "minutes_left": 180, "conversations": 54 }
Webhook payload & headers
X-Naadham-Signature: sha256=<hex>
X-Naadham-Event: booking.created
Idempotency-Key: evt_… # dedupe on this
{ "id":"evt_…", "event":"booking.created", "tenant_id":"t_…", "ts":1781234567,
"data":{ "id":"b_…", "patient_name":"Asha", "patient_phone":"+91…",
"service":"Dental", "requested_time":"2026-07-02T11:30:00", "status":"confirmed" } }
EHR / HMS integration (FHIR)
A confirmed booking can be pushed to your hospital system as a standards-based FHIR R4 Appointment, or as a generic signed webhook for non-FHIR systems.
{
"resourceType":"Appointment", "status":"booked",
"description":"Dental", "start":"2026-07-02T11:30:00",
"participant":[{"actor":{"display":"Asha"},"status":"accepted"}],
"identifier":[{"system":"https://naadham.app/booking","value":"b_…"}]
}
Errors & rate limits
| Status | Meaning |
|---|---|
400 | Bad request (missing/invalid fields) |
401 | Missing/invalid API key |
403 | Not allowed (e.g. admin-only) |
404 | Not found |
429 | Rate limited — back off using the Retry-After header |