UMAI CRM · Dasturchilar uchun
Ochiq API v1
Tashqi tizimingiz (sayt, mobil ilova, ichki CRM) UMAI bilan server-to-server ishlashi uchun:
- Bilim kartalarini sinxronlash: AI agent javob beradigan ma'lumotlar (FAQ, tariflar, qoidalar) sizning tizimingizdan avtomatik yangilanadi.
- API kanal: saytingiz yoki ilovangizdagi support oynasidan mijoz xabari UMAI suhbatlariga tushadi, 24/7 AI agent yoki operator javob beradi, javob esa serveringizga imzolangan callback bilan qaytadi.
Base URL: https://app.umari.uz/public/v1. Versiya v1: buzuvchi o'zgarishlar faqat v2 da bo'ladi (yangi ixtiyoriy maydonlar qo'shilishi mumkin).
API kalit va kanal UMAI ichida yaratiladi: kirish, so'ng Integratsiyalar va Chat kanallari sahifalari.
1. Nega login tokeni emas, API kalit
UMAI login tokeni 2 soatlik va "bitta qurilma" qoidasi bilan ishlaydi: server undan foydalansa operator seanslari yopilib ketadi. Shuning uchun tashqi tizimlar uchun alohida, doimiy va cheklangan huquqli API kalit ishlatiladi. API faqat serverdan chaqiriladi: brauzer yoki mobil ilova ichiga kalit qo'yilmaydi (CORS ochilmaydi).
2. API kalit
- UMAI: Integratsiyalar → API kalitlar → Yangi kalit. Nom va huquqlarni (scope) tanlang.
- Kalit (
umai_sk_..., 51 belgi) faqat bir marta ko'rsatiladi. Uni darhol secret manager'ga (yoki server.envga) saqlang. UMAI bazasida faqat xeshi turadi: yo'qolsa tiklab bo'lmaydi, yangisini yarating. - Har so'rovda sarlavha:
Authorization: Bearer umai_sk_.... Kalitni URL'ga (query string) qo'ymang: u e'tiborga olinmaydi. - Almashtirish (rotatsiya): yangi kalit yarating → tizimingizga deploy qiling → eski kalitni "Bekor qilish". Bekor qilish darhol kuchga kiradi.
- Kompaniyada bir vaqtda 10 tagacha faol kalit bo'ladi. Ro'yxatda kalit prefiksi (
umai_sk_Ab3x) va oxirgi ishlatilgan vaqt ko'rinadi.
| Scope | Nima beradi |
|---|---|
knowledge | Bilim kartalarini sinxronlash (/knowledge/*) |
chat | API kanal xabarlari (/channels/*) |
Funksiya tarifdagi "API va webhooklar" (api_webhooks) imkoniyati bilan ishlaydi. Tarifda bo'lmasa so'rovlar 403 qaytaradi. Tekshirish: GET /public/v1/me (scope talab qilinmaydi).
curl -s https://app.umari.uz/public/v1/me -H "Authorization: Bearer $UMAI_API_KEY"
# {"success":true,"data":{"key":{"prefix":"umai_sk_Ab3x","name":"Sayt support","scopes":["knowledge","chat"]}}}3. Javob konverti, xatolar va limitlar
Muvaffaqiyat: {"success": true, "data": ...}. Xato: {"success": false, "error": "matn", "code": "KOD", ...qo'shimcha}. Barcha javoblarda Cache-Control: no-store.
| HTTP | code | Ma'nosi |
|---|---|---|
| 400 | VALIDATION | Maydon noto'g'ri (field, sync'da index, externalId ham qaytadi) |
| 400 | CONTEXT_INVALID, CONTEXT_TOO_LARGE | Mijoz konteksti noto'g'ri yoki juda katta |
| 401 | API_KEY_REQUIRED | Authorization: Bearer umai_sk_... sarlavhasi yo'q yoki noto'g'ri formatda |
| 401 | API_KEY_INVALID / API_KEY_REVOKED | Kalit topilmadi / bekor qilingan |
| 403 | COMPANY_<STATUS> | Kompaniya faol emas (masalan COMPANY_SUSPENDED) |
| 403 | PLAN_REQUIRED (reason: FEATURE_NOT_INCLUDED / SUBSCRIPTION_EXPIRED) | Tarifda imkoniyat yo'q yoki obuna tugagan |
| 403 | API_SCOPE (required) | Kalitda shu huquq yo'q |
| 404 | CHANNEL_NOT_FOUND, NOT_FOUND | Kanal (yoki marshrut) topilmadi |
| 409 | IDEMPOTENCY_CONFLICT | Shu messageId boshqa mazmun bilan yuborilgan |
| 409 | IN_PROGRESS | Shu messageId hali bajarilmoqda (Retry-After: 5) |
| 409 | CHAT_DISABLED, CHANNEL_DISABLED | Chat yoki shu kanal UMAI sozlamalarida o'chiq |
| 409 | KNOWLEDGE_LIMIT | Kartalar limiti (API: 300, kompaniyada jami: 500) |
| 429 | RATE_LIMITED | So'rovlar juda ko'p |
| 502 | CHAT_UNREACHABLE | Chat serveri javob bermadi: xuddi shu messageId bilan qayta yuboring |
Limitlar: IP bo'yicha 600 so'rov/daqiqa, kalit bo'yicha 300 so'rov/daqiqa. Javobda RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset sarlavhalari bor. Tana hajmi 1 MB gacha.
4. Bilim kartalari (scope knowledge)
Karta maydonlari: externalId (sizning ID'ingiz: ^[A-Za-z0-9][A-Za-z0-9._:@-]{0,63}$), type (faq | script | product | policy), title (1–200), content (1–20000), active (ixtiyoriy, true/false; yuborilmasa o'zgarmaydi, yangi karta faol bo'ladi).
- API orqali yozilgan kartalar UMAI'da "API" belgisi bilan ko'rinadi: admin ularning matnini o'zgartira olmaydi va o'chira olmaydi (faqat yoqish/o'chirish), mazmun sizning tizimingizdan boshqariladi.
- Qo'lda yozilgan kartalarga API hech qachon tegmaydi: ro'yxat, sync va o'chirish faqat API kartalari bilan ishlaydi.
- Limit: API kartalari 300 tagacha, kompaniyadagi jami kartalar 500 tagacha.
- Matndan
<bilim_kartalari>,<mijoz_konteksti>kabi xizmat teglari va boshqaruv belgilari olib tashlanadi. - AI keyingi javobdayoq yangi ma'lumotni ishlatadi (kesh yo'q).
Bitta karta (upsert):
curl -s -X PUT https://app.umari.uz/public/v1/knowledge/faq-delivery \
-H "Authorization: Bearer $UMAI_API_KEY" -H "Content-Type: application/json" \
-d '{"type":"faq","title":"Yetkazib berish","content":"Toshkent bo'\''ylab 1 kunda, viloyatlarga 3 kunda."}'
# {"success":true,"data":{"externalId":"faq-delivery","result":"created","item":{...}}}
# result: created | updated | unchanged (mazmun bir xil bo'lsa yozilmaydi)Ro'yxat va o'chirish:
curl -s https://app.umari.uz/public/v1/knowledge -H "Authorization: Bearer $UMAI_API_KEY"
# {"items":[{"externalId":"faq-delivery","type":"faq","title":"...","content":"...","active":true,"updatedAt":"..."}],"total":1}
curl -s -X DELETE https://app.umari.uz/public/v1/knowledge/faq-delivery -H "Authorization: Bearer $UMAI_API_KEY"
# {"externalId":"faq-delivery","deleted":true} (yo'q bo'lsa deleted:false: takror chaqirish xavfsiz)To'plam sinxroni (1–100 karta va tana 1 MB gacha, atomar: bitta xato bo'lsa hech biri yozilmaydi):
curl -s -X POST https://app.umari.uz/public/v1/knowledge/sync \
-H "Authorization: Bearer $UMAI_API_KEY" -H "Content-Type: application/json" \
-d '{"items":[{"externalId":"plan-pro","type":"product","title":"Pro tarif","content":"Oyiga 300 000 so'\''m."}],"deleteMissing":false}'
# {"created":1,"updated":0,"unchanged":0,"deleted":0}deleteMissing: true: ro'yxatda yo'q API kartalari o'chiriladi (to'liq ko'zgu). Bo'sh items rad etiladi (tasodifiy hammasini o'chirishdan himoya).
deleteMissing faqat barcha API kartalaringiz bitta so'rovga sig'sa ishlaydi (≤100 ta va ≤1 MB): har so'rov o'zida yo'q API kartalarini o'chiradi, shuning uchun bo'laklab yuborishda deleteMissing:true oldingi bo'laklarni o'chirib yuboradi. Kartalar ko'p bo'lsa deleteMissing:false bilan bo'laklab yuboring va keraksizlarini DELETE /knowledge/{externalId} bilan o'chiring.5. API kanal (scope chat)
UMAI: Chat kanallari → API kanal → Ulash. Nom va (ixtiyoriy) callback URL kiriting. Natijada: channelId va imzo siri (whsec_..., faqat bir marta ko'rsatiladi). Callback URL bo'lmasa kanal "faqat pull" rejimida ishlaydi.
Oqim: mijoz sizning oynangizda yozadi → serveringiz POST /channels/{channelId}/messages → xabar UMAI suhbatlarida paydo bo'ladi → 24/7 AI agent (yoqilgan bo'lsa) yoki operator javob beradi → javob callback URL'ingizga keladi.
curl -s -X POST https://app.umari.uz/public/v1/channels/3/messages \
-H "Authorization: Bearer $UMAI_API_KEY" -H "Content-Type: application/json" \
-d '{"messageId":"m-9f1c2","user":{"id":"u-5512","name":"Dilnoza"},"text":"Sinov muddatim qachon tugaydi?","context":{"plan":"Pro","trial_days_left":3}}'
# {"success":true,"data":{"status":"recorded","duplicate":false,"messageId":"m-9f1c2","conversationId":812,"umaiMessageId":99101}}messageIdmajburiy idempotentlik kaliti (^[A-Za-z0-9][A-Za-z0-9._:@-]{0,127}$). Qayta yuborishda aynan shu qiymatni ishlating: bir xilmessageId+ bir xil mazmun →200 duplicate:true(xabar ikki marta yozilmaydi); boshqa mazmun →409 IDEMPOTENCY_CONFLICT.502 CHAT_UNREACHABLEyoki409 IN_PROGRESSbo'lsa biroz kutib (masalan 5 s, keyin oshirib) xuddi shumessageIdbilan qayta yuboring. Idempotentlik oynasi 30 kun.user.id: sizning foydalanuvchi ID'ingiz (xuddi shu format). Bitta(channelId, user.id)= UMAI'da bitta suhbat.user.name80 belgigacha.text1–4000 belgi, v1 da faqat matn (attachmentsqabul qilinmaydi).- Mijoz telefoni so'ralmaydi va yuborilmaydi. API kanal suhbati UMAI'da lid (buyurtma kartasi) yaratmaydi.
- Operator taqsimlash kompaniya sozlamasi bo'yicha: smenada onlayn operator bo'lsa suhbat unga biriktiriladi va AI jim turadi; operator bo'lmasa (masalan kechasi) 24/7 AI agent javob beradi.
- Ma'lum cheklov: juda kam holatda (chat serveri javobi kechikib, aslida xabar yozilgan bo'lsa) qayta yuborish chat serverida ikkinchi nusxa yaratishi mumkin.
6. Mijoz konteksti (ixtiyoriy)
context: shu mijoz haqidagi ichki ma'lumot (tarif, sinov kunlari, til). Mijozga ko'rinmaydi, xabarlar tarixiga yozilmaydi, callback'larga chiqmaydi: faqat 24/7 AI agent uni ma'lumot sifatida ishlatadi ("Sinovingiz 3 kundan keyin tugaydi").
- Tekis obyekt, ko'pi bilan 20 kalit, kalit
^[a-z][a-z0-9_]{0,39}$. - Qiymat: matn (200 belgigacha, ortig'i kesiladi), son yoki
true/false. Ichma-ich obyekt va ro'yxat mumkin emas. JSON 2000 belgigacha. - Yuborilsa avvalgisini to'liq almashtiradi;
"context": nulltozalaydi; yuborilmasa o'zgarmaydi. - Parol, karta raqami, token yoki boshqa maxfiy ma'lumot yubormang.
7. Callback (UMAI → sizning serveringiz)
POST <callbackUrl>
Content-Type: application/json
User-Agent: UMAI-Webhook/1
X-Umai-Event: message.created
X-Umai-Event-Id: evt_1532 (barcha urinishlarda bir xil)
X-Umai-Timestamp: 1792569249 (shu urinishning unix soniyasi)
X-Umai-Attempt: 2
X-Umai-Signature: sha256=<hex HMAC_SHA256(signingSecret, X-Umai-Timestamp + "." + rawBody)>{"id":"evt_1532","type":"message.created","createdAt":"2026-10-21T09:14:09.120Z","channelId":3,
"conversation":{"id":812,"userId":"u-5512"},
"message":{"id":99102,"text":"Sinovingiz 3 kundan keyin tugaydi.","sender":"bot","createdAt":"2026-10-21T09:14:08.950Z","hasAttachments":false}}sender: bot (AI javobi, salomlashish, "operator tez orada javob beradi") yoki operator. Operator ismi, kompaniya ma'lumotlari va mijoz konteksti yuborilmaydi. Sinov tugmasi {"id":"evt_ping_<uuid>","type":"ping","createdAt":"...","channelId":3} yuboradi (xuddi shunday imzolanadi).
Qabul qiluvchi shartnomasi:
- Imzoni xom tana (rawBody, JSON parse qilishdan oldin) ustida tekshiring, solishtirish
timingSafeEqual/hmac.compare_digestbilan. |hozir − X-Umai-Timestamp| ≤ 300soniya bo'lsin (eski so'rovni qayta yuborishdan himoya).X-Umai-Event-Idbo'yicha dedupe qiling: yetkazish at-least-once (bir event bir necha marta kelishi mumkin).- Tartib kafolatlanmaydi: xabarlarni
message.createdAtbo'yicha saralang. - 5 soniya ichida 2xx qaytaring (og'ir ishni navbatga qo'ying). Redirect kuzatilmaydi (3xx = muvaffaqiyatsiz). Javob tanasi o'qilmaydi.
- Productionda faqat
https://; ichki yoki xususiy manzillar (localhost, 10.x, 192.168.x, 169.254.x, ...) bloklanadi.
Qayta urinish: 2xx bo'lmagan har qanday javob, timeout yoki tarmoq xatosida 10 s, 1 daq, 5 daq, 15 daq, 1 soat, 3 soat, 6 soat, 12 soat keyin (jami 9 urinish, ~22 soat). Undan keyin yetkazish "failed" bo'ladi: UMAI'da kanal kartasidagi "Qayta yuborish" tugmasi oxirgi 7 kundagi muvaffaqiyatsizlarini qayta navbatga qo'yadi (Event-Id o'zgarmaydi). Imzo siri almashtirilgandan keyingi urinishlar yangi sir bilan imzolanadi. Timeout yoki tarmoq xatosida shu kanalning navbatdagi boshqa javoblari 30 soniyaga kechiktiriladi.
Node.js (Express) namunasi:
const crypto = require("crypto");
const express = require("express");
const app = express();
const SECRET = process.env.UMAI_SIGNING_SECRET; // whsec_...
const seen = new Set(); // productionda: bazadagi unique jadval
app.post("/umai/callback", express.raw({ type: "application/json" }), (req, res) => {
const ts = String(req.get("X-Umai-Timestamp") || "");
const sig = String(req.get("X-Umai-Signature") || "");
const raw = req.body.toString("utf8");
const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(`${ts}.${raw}`).digest("hex");
const ok = sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
if (!ok || !/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
const event = JSON.parse(raw);
if (seen.has(event.id)) return res.sendStatus(200);
seen.add(event.id);
if (event.type === "message.created") {
// event.conversation.userId foydalanuvchisiga event.message.text ni ko'rsating (navbat orqali)
}
res.sendStatus(200);
});Python (Flask) namunasi:
import hashlib, hmac, os, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["UMAI_SIGNING_SECRET"].encode()
@app.post("/umai/callback")
def umai_callback():
ts = request.headers.get("X-Umai-Timestamp", "")
sig = request.headers.get("X-Umai-Signature", "")
raw = request.get_data() # xom tana (bytes)
expected = "sha256=" + hmac.new(SECRET, ts.encode() + b"." + raw, hashlib.sha256).hexdigest()
if not ts.isdigit() or abs(time.time() - int(ts)) > 300 or not hmac.compare_digest(sig, expected):
abort(401)
event = request.get_json()
# event["id"] bo'yicha dedupe; event["message"]["text"] -> event["conversation"]["userId"]
return "", 200PHP namunasi:
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_UMAI_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_UMAI_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, getenv('UMAI_SIGNING_SECRET'));
if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300 || !hash_equals($expected, $sig)) { http_response_code(401); exit; }
$event = json_decode($raw, true);
http_response_code(200);8. Pull (zaxira)
Callback'lar uzilib qolgan bo'lsa bo'shliqni to'ldirish yoki callback URL'siz ("faqat pull") kanal uchun:
curl -s "https://app.umari.uz/public/v1/channels/3/messages?userId=u-5512&after=99000&limit=50" -H "Authorization: Bearer $UMAI_API_KEY"
# {"conversationId":812,"items":[{"id":99101,"direction":"in","sender":"customer","text":"...","createdAt":"..."},
# {"id":99102,"direction":"out","sender":"bot","text":"...","createdAt":"..."}]}after: oxirgi olingan xabar id si (kursor), limit 1–100 (standart 50, kattasi 100 ga tushiriladi). Noma'lum foydalanuvchi uchun {"conversationId":null,"items":[]}. Ichki izohlar hech qachon chiqmaydi.
9. v1 cheklovlari
- Faqat matnli xabarlar (fayl/rasm yo'q).
- API kanal lid yaratmaydi; mijoz telefoni so'ralmaydi.
- Smenada onlayn operator bo'lsa suhbat operatorga biriktiriladi va AI jim turadi ("faqat AI" rejimi keyingi bosqichda).
- Mijoz konteksti faqat 24/7 inbox agentida ishlatiladi (kechki agentda emas) va operator panelida ko'rsatilmaydi.
- Bitta kompaniyada 5 tagacha API kanal; kalit kanalga bog'lanmaydi (kompaniyadagi istalgan kanal
channelIdbilan).