Хөгжүүлэгчийн баримт · Хувилбар 2026-10-14 · Base URL https://api.chatnova.mn/v1
Товчхондоо: Бот Messenger, Instagram-аас захиалга авмагц ChatNova таны серверийн хаяг руу JSON илгээнэ (webhook). Таны систем REST API-аар захиалгыг уншиж, «баталгаажсан / хүргэлтэд гарсан / хүргэгдсэн» төлөв тавихад харилцагчид Messenger-ээр мэдэгдэл автоматаар очно. Бараа, үлдэгдлийг ч API-аар шинэчилнэ.
cn_live_… нэг л удаа харагдана — хуулж аваарай. Бизнес, Про багцад багтдаг.https:// хаяг. Нууц түлхүүр whsec_… нэг удаа харагдана.ping үйл явдал авна. Дараа нь жинхэнэ захиалга бүр order.created-оор ирнэ.Хялбар хувилбар хэрэгтэй юу? Google Sheets толь (Бараа · захиалга → Тохиргоо) захиалга бүрийг хүснэгтэд бичдэг — кодгүй. Zapier, Make, n8n-д webhook хаягаа «Catch hook» болгон ашиглаж болно.
Бүх REST хүсэлтэд толгой: Authorization: Bearer cn_live_… (эсвэл X-Api-Key). Түлхүүр нэг байгууллагад хамаарна — зөвхөн тэр байгууллагын захиалга, бараа харагдана. Түлхүүр алдагдвал порталаас цуцлаад шинээр үүсгэнэ.
curl https://api.chatnova.mn/v1/me \
-H "Authorization: Bearer cn_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Хязгаар: нэг түлхүүрд минутад 120 хүсэлт (429 + Retry-After: 60). Түлхүүрийг хөтөч, мобайл апп дотор хэзээ ч тавихгүй — зөвхөн сервер талд.
| Үйл явдал | Хэзээ |
|---|---|
order.created | Бот захиалга (эсвэл цаг захиалгын хүсэлт) бүртгэмэгц |
order.updated | Төлөв, төлбөр (QPay орсон), тэмдэглэл, мөшгөлт, гадаад дугаар солигдох бүрд — data.changes-д юу өөрчлөгдсөн нь |
order.assigned | Захиалга жолооч эсвэл хүргэлтийн компанид оноогдох үед (data.order.courier_id; компани бол data.partner_id) |
ping | Порталын «Тест» товч — жишээ захиалгатай |
Хүсэлт: POST, Content-Type: application/json, 10 секундын дотор 2xx хариу хүлээнэ. Хариуны биеийг уншихгүй. Redirect дагахгүй. Зөвхөн https://, нийтийн домэйн.
POST /webhooks/chatnova HTTP/1.1
Host: shop.mn
Content-Type: application/json
User-Agent: ChatNova-Webhooks/1.0
X-ChatNova-Event: order.created
X-ChatNova-Event-Id: evt_3f9c2a7d1b6e4a8f0c21e4d2
X-ChatNova-Delivery: 5b2c… (илгээлт бүрийн id)
X-ChatNova-Attempt: 1
X-ChatNova-Signature: t=1760434212,v1=9b1e…64 hex…
{
"id": "evt_3f9c2a7d1b6e4a8f0c21e4d2",
"type": "order.created",
"api_version": "2026-10-14",
"created_at": "2026-10-14T09:30:12.418Z",
"tenant_id": "af9be6a7-b582-4406-98a5-68478a4d4e35",
"data": {
"order": {
"id": "7c1d9e3a-2b4f-4c8d-9e0f-1a2b3c4d5e6f",
"number": "CN-000124",
"status": "new",
"kind": "order",
"source": "ai",
"created_at": "2026-10-14T09:30:12.001Z",
"updated_at": "2026-10-14T09:30:12.001Z",
"currency": "MNT",
"total_mnt": 97800,
"paid_mnt": 0,
"payment_mode": "bank_after",
"items": [
{ "id": "c0ff…", "name": "Витамин D3 5000", "qty": 2, "price_mnt": 45000, "total_mnt": 90000 },
{ "id": null, "name": "Хүргэлт", "qty": 1, "price_mnt": 7800, "total_mnt": 7800 }
],
"customer": { "name": "Болд", "phone": "99112233" },
"delivery": { "address": null, "district": "Хан-Уул", "khoroo": "11", "building": "Хотхон 5-р байр", "entrance": "2 орц 45 тоот", "note": null },
"booking": null,
"fields": { "phone": "99112233", "name": "Болд", "district": "Хан-Уул", "khoroo": "11", "building": "Хотхон 5-р байр", "entrance": "2 орц 45 тоот" },
"note": null,
"external_ref": null,
"tracking": null,
"courier_id": null,
"shipped_at": null,
"delivered_at": null,
"channel": { "page_id": "104322281612245", "conversation_id": "9e2b…" }
},
"actor": { "kind": "bot" }
}
}
order.updated дээр нэмэлт: "changes": { "status": { "from": "new", "to": "confirmed" }, "paid_mnt": { "from": 0, "to": 97800 } }. actor.kind: bot · portal (эзэн порталаас) · api (API түлхүүрээр — actor.key_id хамт; өөрийн хийсэн өөрчлөлтийг алгасахад) · payment (QPay) · staff · courier (жолоочийн хуудас) · partner (хүргэлтийн компани — actor.partner_id) · auto (шинэ захиалгыг автоматаар оноох).
X-ChatNova-Event-Id (= id)-г хадгалж, ирсэн id-г алгасна (идемпотент).order.updated нь order.created-оос түрүүлж ирж болно — updated_at-аар харьцуул, эсвэл GET /v1/orders/{id}-ээр одоогийн төлөвийг ав.GET /v1/orders?since=…-ээр нөхөж уншина.X-ChatNova-Signature: t=<unix секунд>,v1=<hex>. v1 = HMAC-SHA256(secret, t + "." + хүсэлтийн бие). Биеийг яг ирсэн байт-аар (JSON-оо дахин угсрахгүй — re-serialize хийхгүй) ашиглана. t нь 5 минутаас хуучин бол татгалзана. Шалгалтгүй хүлээн авч болохгүй — хаяг нийтэд ил, гарын үсэг л ChatNova-гийнх гэж батална.
const crypto = require('crypto');
function verify(secret, header, rawBody) {
const m = /t=(\d+),v1=([0-9a-f]{64})/.exec(header || '');
if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const want = crypto.createHmac('sha256', secret).update(m[1] + '.' + rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(want, 'hex'), Buffer.from(m[2], 'hex'));
}
app.post('/webhooks/chatnova', express.raw({ type: 'application/json' }), (req, res) => {
if (!verify(process.env.CHATNOVA_WEBHOOK_SECRET, req.get('X-ChatNova-Signature'), req.body.toString('utf8'))) return res.sendStatus(401);
const event = JSON.parse(req.body);
if (seen(event.id)) return res.sendStatus(200); // давхардал
if (event.type === 'order.created') createOrderInMySystem(event.data.order);
if (event.type === 'order.updated') updateStatus(event.data.order, event.data.changes);
res.sendStatus(200); // 10 секундын дотор; урт ажлыг дараалалд
});
$raw = file_get_contents('php://input');
$hdr = $_SERVER['HTTP_X_CHATNOVA_SIGNATURE'] ?? '';
if (!preg_match('/t=(\d+),v1=([0-9a-f]{64})/', $hdr, $m) || abs(time() - (int)$m[1]) > 300) { http_response_code(401); exit; }
$want = hash_hmac('sha256', $m[1] . '.' . $raw, $secret);
if (!hash_equals($want, $m[2])) { http_response_code(401); exit; }
$event = json_decode($raw, true);
// $event['type'], $event['data']['order']['number'], ['customer']['phone'], ['items'] …
http_response_code(200);
import hmac, hashlib, time, re
def verify(secret: str, header: str, raw_body: bytes) -> bool:
m = re.search(r't=(\d+),v1=([0-9a-f]{64})', header or '')
if not m or abs(time.time() - int(m.group(1))) > 300:
return False
want = hmac.new(secret.encode(), m.group(1).encode() + b'.' + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(want, m.group(2))
Та хүргэлтийн компани бол дэлгүүр бүртэй тусдаа түлхүүр солилцох шаардлагагүй. chatnova.mn/partners-д бүртгүүлнэ → ChatNova батална (1 ажлын өдөр) → самбарын линк имэйлээр ирнэ → дэлгүүрүүд порталаасаа танай компанийг нэг товчоор холбоно. Танд оноогдсон захиалга л харагдана.
chatnova.mn/partner?t=… — захиалга дэлгүүрээр бүлэглэгдсэн; «Авлаа», «Хүргэгдсэн», «Чадсангүй». Тохиргоо табаас API түлхүүр, webhook хаягаа өөрөө удирдана.order.assigned, order.updated тэнд очно (гарын үсэг 4-р хэсэг, нууц нэг). Payload-д нэмэлт: data.partner_id.Authorization: Bearer cn_partner_… — минутад 300 хүсэлт.| Зам | Юу хийх |
|---|---|
GET/v1/partner/me | Компани, холбогдсон дэлгүүрийн тоо |
GET/v1/partner/shops | Холбогдсон дэлгүүрүүд (id, name, phone, active, pickup) |
GET/v1/partner/orders | Танд оноогдсон захиалга, бүх дэлгүүрээс. Query: status (анхдагч бүгд; таслалаар олон), since, shop_id, limit, offset. Захиалга бүрд shop: {id, name, phone, pickup} нэмэгдэнэ — pickup {address, phone, note} = барааг авах газар (дэлгүүр порталаасаа тохируулна; хоосон бол null). Webhook-ийн data.shop ч ижил |
GET/v1/partner/orders/{id} | Нэг захиалга (uuid) |
PATCH/v1/partner/orders/{id} | status: shipped | delivered (цуцлалтыг дэлгүүр хийнэ), tracking, note, external_ref, notify. Харилцагчид Messenger мэдэгдэл автоматаар |
curl "https://api.chatnova.mn/v1/partner/orders?status=new,confirmed,shipped" -H "Authorization: Bearer $PARTNER_KEY"
curl -X PATCH https://api.chatnova.mn/v1/partner/orders/7c1d9e3a-… -H "Authorization: Bearer $PARTNER_KEY" -H "Content-Type: application/json" \
-d '{"status":"delivered","note":"Хаалган дээр хүлээлгэн өгсөн"}'
| Зам | Юу хийх |
|---|---|
GET/v1/me | Түлхүүр, байгууллага, багц, идэвхтэй webhook тоо |
GET/v1/orders | Захиалгын жагсаалт, сүүлийн эхэнд. Query: status (таслалаар олон), since, until (created_at), updated_since, limit (≤200, анхдагч 50), offset. Хариу { data, has_more, next_offset } |
GET/v1/orders/{id} | id нь uuid эсвэл дугаар CN-000124 (124 ч болно) |
PATCH/v1/orders/{id} | Бие: status (confirmed | shipped | delivered | cancelled), note, external_ref (таны системийн дугаар), tracking {carrier, number, url, eta, note}, notify (анхдагч true — харилцагчид Messenger мэдэгдэл). Хариу { data, notified } |
GET/v1/products | Бараа (идэвхтэй л; include_disabled=1 бүгд). Query: q, category, limit (≤500), offset |
PATCH/v1/products/{id} | id = uuid эсвэл external_id (таны SKU). Бие: stock (0 = дууссан, null = хязгааргүй), price_mnt, list_price_mnt, external_id, enabled |
GET/v1/webhooks | Бүртгэлтэй webhook хаягууд (нууцгүй) |
# Шинэ захиалгуудыг татах
curl "https://api.chatnova.mn/v1/orders?status=new,confirmed&since=2026-10-14T00:00:00Z&limit=100" \
-H "Authorization: Bearer $CHATNOVA_KEY"
# Хүргэлтэд гарсан гэж тэмдэглэх — харилцагч «хүргэлтэд гарлаа 🚚 Ээлж · дугаар EE123» мэдэгдэл авна
curl -X PATCH https://api.chatnova.mn/v1/orders/CN-000124 \
-H "Authorization: Bearer $CHATNOVA_KEY" -H "Content-Type: application/json" \
-d '{"status":"shipped","external_ref":"DLV-7781","tracking":{"carrier":"Ээлж хүргэлт","number":"EE123","url":"https://eelj.mn/t/EE123"}}'
# Бараа дууссан — бот үүнийг зарахаа больж, хүлээлгийн жагсаалтад бүртгэнэ
curl -X PATCH https://api.chatnova.mn/v1/products/SKU-1 \
-H "Authorization: Bearer $CHATNOVA_KEY" -H "Content-Type: application/json" -d '{"stock":0}'
Бүх хариунд X-ChatNova-Version толгой. Цаг ISO 8601 (UTC). Мөнгө бүхэл төгрөг.
| Талбар | Утга |
|---|---|
id, number | uuid; хүнд харагдах дугаар CN-000124 (байгууллага бүрд дараалсан) |
status | new | confirmed | shipped | delivered | cancelled, цаг захиалгад arrived | no_show ч бий (7-р хэсэг) |
kind | order (бараа) · booking (цаг захиалга, хүсэлт — booking талбартай) |
source | ai (бот) · slots · manual (ажилтан гараар) · n8n |
total_mnt, paid_mnt, payment_mode | Нийт, төлсөн дүн (QPay орвол), төлбөрийн горим (none | prepay | full | bank_after …) |
items[] | id (ChatNova барааны uuid — /v1/products-оор external_id/SKU-тай тааруулна), name, qty, price_mnt, total_mnt |
customer | name, phone (8 орон, +976-гүй; цифр биш бол бичсэн чигээрээ) |
delivery | address, district, khoroo, building, entrance, note — бот асуусан талбаруудаас; байхгүй нь null |
booking | { service, date, time } эсвэл null |
fields | Ботын асуусан бүх талбар түүхийгээр (phone, name, district … + таны урсгалын өөрийн талбарууд) |
note, external_ref, tracking | Эзний/таны тэмдэглэл; таны системийн дугаар; {carrier, number, url, eta, note, updated_at} |
courier_id, shipped_at, delivered_at | Оноосон жолооч/компанийн courier id; хүргэлтэд анх гарсан, хүргэгдсэн цаг (ISO). Оноогдоогүй бол null |
channel | page_id (Facebook Page), conversation_id |
| Төлөв | Утга | Харилцагчид (Messenger) |
|---|---|---|
new | Бот бүртгэсэн | — |
confirmed | Баталгаажсан (QPay орсон, эзэн/таны систем батласан) | «… захиалга БАТАЛГААЖЛАА ✅ Нийт …₮» |
shipped | Хүргэлтэд гарсан | «… ХҮРГЭЛТЭД ГАРЛАА 🚚 Хүргэлт: {carrier} · дугаар {number}» |
delivered | Хүргэгдсэн | «… ХҮРГЭГДЛЭЭ 🚚✅» + 1–5 үнэлгээний товч |
cancelled | Цуцлагдсан (үлдэгдэл буцна) | «… цуцлагдлаа» |
arrived, no_show | Цаг захиалга: ирсэн / ирээгүй (зөвхөн портал) | — |
Мэдэгдэл Meta-гийн 24 цагийн цонх нээлттэй бол шууд, хаалттай бол зөвшөөрөгдсөн загвараар явна; Instagram-д цонх хаалттай бол чимээгүй. Байгууллага «харилцагчид SMS» асаасан бол SMS ч очно. Мэдэгдэл хэрэггүй бол "notify": false. Ижил төлөвийг дахин тавьвал мэдэгдэл давтагдахгүй.
id, external_id (таны SKU — PATCH-аар тавина, дараа нь үүгээр хандана), name, emoji, price_mnt, list_price_mnt (хямдралын өмнөх), stock (null хязгааргүй · 0 дууссан), category, featured, enabled, image_url, aliases[], description, pre_order, updated_at. Үлдэгдэл 0 болоход бот тэр барааг зарахгүй, нэр үнийг хэлж хүлээлгийн жагсаалтад бүртгэнэ; дахин ирэхэд мэдэгдэнэ.
| HTTP | error | Шалтгаан |
|---|---|---|
| 400 | bad_request | Талбар буруу — message-д тайлбар, allowed-д зөвшөөрөгдөх утга |
| 401 | unauthorized, invalid_key | Толгой алга / түлхүүр буруу, цуцлагдсан |
| 402 | plan_required | Багцад API алга — Бизнес/Про руу ахиулна |
| 404 | not_found | Захиалга, бараа, зам олдсонгүй (өөр байгууллагынх ч 404) |
| 409 | conflict | external_id давхардсан |
| 429 | rate_limited | Минутад 120 хүсэлт — Retry-After |
| 503 | not_ready | Сервер талын шинэчлэл хүлээгдэж байна — дахин оролдоно |
Хязгаар: байгууллага бүрд 5 идэвхтэй түлхүүр, 3 webhook хаяг. Webhook биеийн хэмжээ захиалгаас хамаарна (ихэвчлэн <10 KB). Илгээлтийн лог 30 хоног хадгалагдана.
Талбар нэмэгдэж болно (хуучин нэр, утга өөрчлөгдөхгүй). Том өөрчлөлт шинэ api_version-той ирж, хуучин нь үргэлжилнэ. Асуулт: hello@chatnova.mn · 7607 3333.
© 2026 ChatNova · Үйлчилгээний нөхцөл · Нууцлал
Developer documentation · Version 2026-10-14 · Base URL https://api.chatnova.mn/v1
In short: the moment the bot takes an order on Messenger or Instagram, ChatNova POSTs JSON to your server (webhook). Your system reads orders over REST and sets “confirmed / shipped / delivered”; the customer is told on Messenger automatically. Products and stock can be updated over the API as well.
cn_live_… is shown once — copy it. Included in Business and Pro.https:// URL. The signing secret whsec_… is shown once.ping. From then on every real order arrives as order.created.Need something simpler? The Google Sheets mirror (Products · orders → Settings) writes every order to a spreadsheet, no code. Zapier, Make or n8n can use the webhook URL as a “catch hook”.
Every REST request carries Authorization: Bearer cn_live_… (or X-Api-Key). A key belongs to one business — only its orders and products are visible. If a key leaks, revoke it in the portal and create a new one.
curl https://api.chatnova.mn/v1/me \
-H "Authorization: Bearer cn_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Limit: 120 requests per minute per key (429 with Retry-After: 60). Never ship the key inside a browser or mobile app — server side only.
| Event | When |
|---|---|
order.created | As soon as the bot records an order (or a booking request) |
order.updated | Whenever status, payment (QPay received), note, tracking or external reference changes — data.changes says what |
order.assigned | When an order is handed to a courier or a delivery partner (data.order.courier_id; for partners data.partner_id) |
ping | The portal “Test” button, with a sample order |
Request: POST, Content-Type: application/json; a 2xx answer is expected within 10 seconds. The response body is ignored. Redirects are not followed. Only https:// on a public domain.
POST /webhooks/chatnova HTTP/1.1
Host: shop.mn
Content-Type: application/json
User-Agent: ChatNova-Webhooks/1.0
X-ChatNova-Event: order.created
X-ChatNova-Event-Id: evt_3f9c2a7d1b6e4a8f0c21e4d2
X-ChatNova-Delivery: 5b2c… (id of this delivery attempt series)
X-ChatNova-Attempt: 1
X-ChatNova-Signature: t=1760434212,v1=9b1e…64 hex…
{
"id": "evt_3f9c2a7d1b6e4a8f0c21e4d2",
"type": "order.created",
"api_version": "2026-10-14",
"created_at": "2026-10-14T09:30:12.418Z",
"tenant_id": "af9be6a7-b582-4406-98a5-68478a4d4e35",
"data": {
"order": {
"id": "7c1d9e3a-2b4f-4c8d-9e0f-1a2b3c4d5e6f",
"number": "CN-000124",
"status": "new",
"kind": "order",
"source": "ai",
"created_at": "2026-10-14T09:30:12.001Z",
"updated_at": "2026-10-14T09:30:12.001Z",
"currency": "MNT",
"total_mnt": 97800,
"paid_mnt": 0,
"payment_mode": "bank_after",
"items": [
{ "id": "c0ff…", "name": "Vitamin D3 5000", "qty": 2, "price_mnt": 45000, "total_mnt": 90000 },
{ "id": null, "name": "Delivery", "qty": 1, "price_mnt": 7800, "total_mnt": 7800 }
],
"customer": { "name": "Bold", "phone": "99112233" },
"delivery": { "address": null, "district": "Khan-Uul", "khoroo": "11", "building": "Block 5", "entrance": "Entrance 2, apt 45", "note": null },
"booking": null,
"fields": { "phone": "99112233", "name": "Bold", "district": "Khan-Uul", "khoroo": "11", "building": "Block 5", "entrance": "Entrance 2, apt 45" },
"note": null,
"external_ref": null,
"tracking": null,
"courier_id": null,
"shipped_at": null,
"delivered_at": null,
"channel": { "page_id": "104322281612245", "conversation_id": "9e2b…" }
},
"actor": { "kind": "bot" }
}
}
order.updated adds "changes": { "status": { "from": "new", "to": "confirmed" }, "paid_mnt": { "from": 0, "to": 97800 } }. actor.kind: bot · portal (owner in the portal) · api (an API key, with actor.key_id — skip your own changes) · payment (QPay) · staff · courier (courier page) · partner (delivery company — actor.partner_id) · auto (auto-assign of new orders).
X-ChatNova-Event-Id (= id) and skip ids you have seen (idempotency).order.updated may overtake its order.created — compare updated_at, or fetch the current state with GET /v1/orders/{id}.GET /v1/orders?since=….X-ChatNova-Signature: t=<unix seconds>,v1=<hex> where v1 = HMAC-SHA256(secret, t + "." + raw request body). Use the body exactly as received (do not re-serialise the JSON). Reject if t is older than 5 minutes. Never accept unverified requests — the URL is public; only the signature proves it came from ChatNova.
const crypto = require('crypto');
function verify(secret, header, rawBody) {
const m = /t=(\d+),v1=([0-9a-f]{64})/.exec(header || '');
if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const want = crypto.createHmac('sha256', secret).update(m[1] + '.' + rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(want, 'hex'), Buffer.from(m[2], 'hex'));
}
app.post('/webhooks/chatnova', express.raw({ type: 'application/json' }), (req, res) => {
if (!verify(process.env.CHATNOVA_WEBHOOK_SECRET, req.get('X-ChatNova-Signature'), req.body.toString('utf8'))) return res.sendStatus(401);
const event = JSON.parse(req.body);
if (seen(event.id)) return res.sendStatus(200); // duplicate
if (event.type === 'order.created') createOrderInMySystem(event.data.order);
if (event.type === 'order.updated') updateStatus(event.data.order, event.data.changes);
res.sendStatus(200); // within 10 s; queue long work
});
$raw = file_get_contents('php://input');
$hdr = $_SERVER['HTTP_X_CHATNOVA_SIGNATURE'] ?? '';
if (!preg_match('/t=(\d+),v1=([0-9a-f]{64})/', $hdr, $m) || abs(time() - (int)$m[1]) > 300) { http_response_code(401); exit; }
$want = hash_hmac('sha256', $m[1] . '.' . $raw, $secret);
if (!hash_equals($want, $m[2])) { http_response_code(401); exit; }
$event = json_decode($raw, true);
// $event['type'], $event['data']['order']['number'], ['customer']['phone'], ['items'] …
http_response_code(200);
import hmac, hashlib, time, re
def verify(secret: str, header: str, raw_body: bytes) -> bool:
m = re.search(r't=(\d+),v1=([0-9a-f]{64})', header or '')
if not m or abs(time.time() - int(m.group(1))) > 300:
return False
want = hmac.new(secret.encode(), m.group(1).encode() + b'.' + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(want, m.group(2))
A delivery company does not need a separate key per shop. Register at chatnova.mn/partners → ChatNova approves (one business day) → the dashboard link arrives by email → shops connect your company from their portal with one click. You see only orders assigned to you.
chatnova.mn/partner?t=… — orders grouped by shop; “Picked up”, “Delivered”, “Failed”. The Settings tab manages your API key and webhook URL.order.assigned and order.updated from every connected shop (signature as in section 4, one secret). Extra field: data.partner_id.Authorization: Bearer cn_partner_… — 300 requests per minute.| Route | What it does |
|---|---|
GET/v1/partner/me | Company and number of connected shops |
GET/v1/partner/shops | Connected shops (id, name, phone, active, pickup) |
GET/v1/partner/orders | Orders assigned to you, across shops. Query: status (default all; comma list), since, shop_id, limit, offset. Each order carries shop: {id, name, phone, pickup} — pickup {address, phone, note} is where to collect the parcel (set by the shop in its portal; null if unset). Webhook data.shop is the same object |
GET/v1/partner/orders/{id} | One order (uuid) |
PATCH/v1/partner/orders/{id} | status: shipped | delivered (cancellation is the shop’s), tracking, note, external_ref, notify. The customer is told on Messenger automatically |
curl "https://api.chatnova.mn/v1/partner/orders?status=new,confirmed,shipped" -H "Authorization: Bearer $PARTNER_KEY"
curl -X PATCH https://api.chatnova.mn/v1/partner/orders/7c1d9e3a-… -H "Authorization: Bearer $PARTNER_KEY" -H "Content-Type: application/json" \
-d '{"status":"delivered","note":"Handed over at the door"}'
| Route | What it does |
|---|---|
GET/v1/me | Key, business, plan, number of active webhooks |
GET/v1/orders | Orders, newest first. Query: status (comma list), since, until (created_at), updated_since, limit (≤200, default 50), offset. Returns { data, has_more, next_offset } |
GET/v1/orders/{id} | id is the uuid or the number CN-000124 (124 works too) |
PATCH/v1/orders/{id} | Body: status (confirmed | shipped | delivered | cancelled), note, external_ref (your own id), tracking {carrier, number, url, eta, note}, notify (default true — Messenger message to the customer). Returns { data, notified } |
GET/v1/products | Products (enabled only; include_disabled=1 for all). Query: q, category, limit (≤500), offset |
PATCH/v1/products/{id} | id = uuid or external_id (your SKU). Body: stock (0 = sold out, null = unlimited), price_mnt, list_price_mnt, external_id, enabled |
GET/v1/webhooks | Registered webhook endpoints (without secrets) |
# Pull new orders
curl "https://api.chatnova.mn/v1/orders?status=new,confirmed&since=2026-10-14T00:00:00Z&limit=100" \
-H "Authorization: Bearer $CHATNOVA_KEY"
# Mark as shipped — the customer gets “out for delivery 🚚 Eelj · EE123” on Messenger
curl -X PATCH https://api.chatnova.mn/v1/orders/CN-000124 \
-H "Authorization: Bearer $CHATNOVA_KEY" -H "Content-Type: application/json" \
-d '{"status":"shipped","external_ref":"DLV-7781","tracking":{"carrier":"Eelj delivery","number":"EE123","url":"https://eelj.mn/t/EE123"}}'
# Sold out — the bot stops selling it and offers a waitlist instead
curl -X PATCH https://api.chatnova.mn/v1/products/SKU-1 \
-H "Authorization: Bearer $CHATNOVA_KEY" -H "Content-Type: application/json" -d '{"stock":0}'
Every response carries X-ChatNova-Version. Times are ISO 8601 (UTC). Money is whole tugrik (MNT).
| Field | Meaning |
|---|---|
id, number | uuid; human-readable number CN-000124 (sequential per business) |
status | new | confirmed | shipped | delivered | cancelled; bookings also arrived | no_show (section 7) |
kind | order (goods) · booking (appointment or request — has a booking field) |
source | ai (bot) · slots · manual (staff) · n8n |
total_mnt, paid_mnt, payment_mode | Total, amount paid (QPay), payment mode (none | prepay | full | bank_after …) |
items[] | id (ChatNova product uuid — map to your SKU via /v1/products external_id), name, qty, price_mnt, total_mnt |
customer | name, phone (8 digits, no +976; left as typed if not numeric) |
delivery | address, district, khoroo, building, entrance, note — from the fields the bot asked; missing ones are null |
booking | { service, date, time } or null |
fields | Every field the bot collected, raw (phone, name, district … plus your flow’s custom fields) |
note, external_ref, tracking | Owner/your note; your system’s id; {carrier, number, url, eta, note, updated_at} |
courier_id, shipped_at, delivered_at | Assigned courier / partner courier id; first shipped and delivered timestamps (ISO). null when unassigned |
channel | page_id (Facebook Page), conversation_id |
| Status | Meaning | Customer (Messenger) |
|---|---|---|
new | Recorded by the bot | — |
confirmed | Confirmed (QPay received, owner or your system confirmed) | “… order CONFIRMED ✅ Total …₮” |
shipped | Out for delivery | “… OUT FOR DELIVERY 🚚 Carrier: {carrier} · no. {number}” |
delivered | Delivered | “… DELIVERED 🚚✅” + 1–5 rating buttons |
cancelled | Cancelled (stock is returned) | “… was cancelled” |
arrived, no_show | Bookings: showed up / did not (portal only) | — |
Messages go out immediately while Meta’s 24-hour window is open, otherwise through an approved template; on Instagram with a closed window nothing is sent. If the business enabled “customer SMS”, an SMS goes too. Pass "notify": false to stay silent. Setting the same status again does not repeat the message.
id, external_id (your SKU — set it via PATCH, then address products by it), name, emoji, price_mnt, list_price_mnt (before discount), stock (null unlimited · 0 sold out), category, featured, enabled, image_url, aliases[], description, pre_order, updated_at. At stock 0 the bot stops selling the item, still quotes name and price, and offers a waitlist; customers are told when it is back.
| HTTP | error | Why |
|---|---|---|
| 400 | bad_request | Invalid field — see message, allowed values in allowed |
| 401 | unauthorized, invalid_key | Missing header / wrong or revoked key |
| 402 | plan_required | API not in the plan — upgrade to Business/Pro |
| 404 | not_found | Order, product or route not found (another business’s records are 404 too) |
| 409 | conflict | Duplicate external_id |
| 429 | rate_limited | 120 requests per minute — see Retry-After |
| 503 | not_ready | Server-side update pending — retry later |
Limits: 5 active keys and 3 webhook endpoints per business. Webhook bodies are usually under 10 KB. The delivery log is kept for 30 days.
Fields may be added (existing names and meanings do not change). Breaking changes arrive under a new api_version while the old one keeps working. Questions: hello@chatnova.mn · +976 7607 3333.