Hesap SDK
Mijozni o'z tizimingizdan Hesap'da ro'yxatdan o'tkazing, shablon asosida shartnoma tuzing va mijozga uni saytingiz ichida imzolating. Mijoz Hesap'ga kirmaydi va saytingizni tark etmaydi.
- Base URL
- https://sdk.hesap.uz/v1
- Autentifikatsiya
- Authorization: Bearer …
- OpenAPI spec
- sdk.hesap.uz/api-docs
- Format
- JSON, UTF-8
Tezkor boshlash
Server tomonidagi so'rovlar Authorization: Bearer token bilan ishlaydi. Tokenni
appId va appSecret evaziga olasiz. Iframe esa tokensiz ochiladi —
unga imzolash sessiyasi ruxsat beradi.
- Token oling
POST /auth/token— appId va appSecret evaziga 1 soatlik token beriladi. - Mijozni ro'yxatdan o'tkazing
POST /clients— PINFL, F.I.Sh., telefon va pasport ma'lumotlari. Takror chaqirish xavfsiz. - Shartnoma tuzing
POST /contracts— shablon, taraflar, summa va to'lov jadvali. - Imzolash sessiyasini oching
POST /contracts/{id}/sign-sessions— javobda iframe uchunurlqaytadi. - Iframe'ni ko'rsatingMijoz shartnomani o'qiydi va SMS kodi, MyID yoki E-IMZO bilan imzolaydi.
- Natijani olingIframe'dan
SIGNEDxabari keladi, serveringizgaCONTRACT_SIGNEDwebhook yuboriladi.
# 0. Token → {"accessToken":"sdkt_…","tokenType":"Bearer","expiresIn":3600}
TOKEN=$(curl -s -X POST https://sdk.hesap.uz/v1/auth/token \
-H "Content-Type: application/json" \
-d "{\"appId\":\"$HESAP_APP_ID\",\"appSecret\":\"$HESAP_APP_SECRET\"}" | jq -r .accessToken)
# 1. Mijoz
curl -X POST https://sdk.hesap.uz/v1/clients \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"in":"31234567890123","firstName":"Aziz","lastName":"Karimov","phone":"998901234567","passport":"AA1234567"}'
# 2. Shartnoma → {"id":"9b3f7c21-..."}
curl -X POST https://sdk.hesap.uz/v1/contracts \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"templateId":"0f0c1f2e-8a41-4d02-9d55-2f7c1b6f9a30","buyerIn":"31234567890123","price":12500000,"currency":"UZS"}'
# 3. Imzolash sessiyasi → {"url":"https://sdk.hesap.uz/sign/…"}
curl -X POST https://sdk.hesap.uz/v1/contracts/9b3f7c21-.../sign-sessions \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"signerIn":"31234567890123","parentOrigin":"https://shop.example.uz"}'
const BASE = "https://sdk.hesap.uz/v1";
let token = null, tokenExp = 0;
// Token 1 soat amal qiladi — keshlaymiz va tugashidan bir daqiqa oldin yangilaymiz.
async function getToken() {
if (token && Date.now() < tokenExp - 60_000) return token;
const r = await fetch(`${BASE}/auth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ appId: process.env.HESAP_APP_ID, appSecret: process.env.HESAP_APP_SECRET }),
});
if (!r.ok) throw new Error((await r.json()).message);
const t = await r.json();
token = t.accessToken; tokenExp = Date.now() + t.expiresIn * 1000;
return token;
}
const api = async (path, body) => {
const r = await fetch(BASE + path, {
method: "POST",
headers: { Authorization: `Bearer ${await getToken()}`, "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (!r.ok) throw new Error((await r.json()).message);
return r.json();
};
await api("/clients", { in: "31234567890123", firstName: "Aziz", lastName: "Karimov",
phone: "998901234567", passport: "AA1234567" });
const { id } = await api("/contracts", {
templateId: "0f0c1f2e-8a41-4d02-9d55-2f7c1b6f9a30",
buyerIn: "31234567890123", price: 12500000, currency: "UZS",
});
const session = await api(`/contracts/${id}/sign-sessions`, {
signerIn: "31234567890123", parentOrigin: "https://shop.example.uz",
});
// session.url — sahifangizdagi iframe'ga bering
Autentifikatsiya
Hesap sizga ikkita qiymat beradi: appId (ochiq identifikator) va appSecret
(maxfiy). Ularni Hesap administratori hamkorlik kelishuvi asosida beradi. appSecret
faqat bir marta ko'rsatiladi — uni serverda, maxfiy sozlamalarda saqlang, brauzer yoki mobil
ilova kodiga qo'shmang.
Har bir so'rovdan oldin secret yubormaysiz: avval POST /auth/token bilan 1 soatlik
token olasiz, keyin uni Authorization: Bearer <accessToken> headerida yuborasiz.
Token muddati tugasa yoki 401 kelsa, yangi token olib so'rovni takrorlang.
Shartnomalar ilova egasi nomidan tuziladi: taraflardan biri ilova egasi bo'lishi kerak. Bo'sh qoldirilgan taraf o'rniga ilova egasi qo'yiladi.
| Huquq | Nimaga ruxsat beradi |
|---|---|
CLIENTS_WRITE | Mijozni ro'yxatdan o'tkazish |
CLIENTS_READ | Mijozni PINFL/STIR bo'yicha tekshirish |
TEMPLATES_READ | Shablonlar va ularning maydonlari |
CONTRACTS_WRITE | Shartnoma tuzish |
CONTRACTS_READ | Shartnoma holati va PDF |
CONTRACTS_SIGN | Imzolash sessiyasini ochish va holatini ko'rish |
Ilovaga barcha shablonlar yoki faqat tanlanganlari ruxsat etiladi. Ruxsat berilmagan shablon bilan
ishlashga urinish 403 qaytaradi.
Umumiy qoidalar
- Identifikator —
in: jismoniy shaxs uchun 14 xonali PINFL, yuridik shaxs uchun 9 xonali STIR. - Sanalar — ISO 8601, UTC:
2026-10-18T00:00:00Z. Pasport va tug'ilgan sana:YYYY-MM-DD. - Telefon — mamlakat kodi bilan, faqat raqamlar:
998901234567(+, bo'sh joy va chiziqcha olib tashlanadi). - Valyuta —
UZS,USD,RUB. - Xato javobida doim
messagemaydoni bo'ladi — uni foydalanuvchiga ko'rsatish mumkin.
Endpointlar
/auth/token
ochiqappId va appSecret evaziga access token olish. Boshqa hamma so'rovlar shu token bilan ishlaydi.
| Maydon | Turi | Izoh |
|---|---|---|
appId majburiy | string | app_… |
appSecret majburiy | string | sks_… |
{
"accessToken": "sdkt_Qm9v7Lx2…",
"tokenType": "Bearer",
"expiresIn": 3600
}appId yoki appSecret noto'g'ri bo'lsa 401 qaytadi (qaysi biri noto'g'ri ekani aytilmaydi).
Ilova bekor qilingan yoki muddati o'tgan bo'lsa 403.
/clients
CLIENTS_WRITEMijozni ro'yxatdan o'tkazish.
Takror chaqirish xavfsiz. Shu in bilan mijoz allaqachon bo'lsa, yangi yozuv ochilmaydi:
mavjud mijozning faqat bo'sh maydonlari to'ldiriladi va o'sha mijoz qaytadi. Hesap'dagi (masalan OneID orqali
tasdiqlangan) ma'lumot qayta yozilmaydi.
| Maydon | Turi | Izoh |
|---|---|---|
in majburiy | string | PINFL (14) yoki STIR (9) |
type | string | CLIENT (standart) yoki COMPANY |
firstName, lastName | string | Jismoniy shaxs uchun majburiy |
midName | string | Otasining ismi |
phone | string | Jismoniy shaxs uchun majburiy — imzolash SMS kodi shu raqamga boradi |
legalName | string | Yuridik shaxs uchun majburiy — tashkilotning to'liq nomi |
passport | string | Seriya va raqam: AA1234567 |
passportIssuedBy | string | Pasportni bergan organ |
passportIssueDate, passportExpiryDate | string | YYYY-MM-DD |
birthday | string | YYYY-MM-DD |
isMan | boolean | Jinsi: true — erkak |
address, email | string |
{
"in": "31234567890123",
"firstName": "Aziz",
"lastName": "Karimov",
"midName": "Olimovich",
"phone": "998901234567",
"passport": "AA1234567",
"passportIssuedBy": "Toshkent sh. Yunusobod IIB",
"passportIssueDate": "2019-05-14",
"passportExpiryDate": "2029-05-13",
"birthday": "1990-03-12",
"isMan": true,
"address": "Toshkent sh., Yunusobod t., 4-kvartal"
}{
"id": "7f3a0c55-1b2e-4d7a-9c0e-5e2d8a1b3c44",
"in": "31234567890123",
"firstName": "Aziz",
"lastName": "Karimov",
"midName": "Olimovich",
"legalName": null,
"type": "CLIENT",
"phone": "998901234567",
"verified": false
}verified: false — siz yuborgan ma'lumot saqlanadi, lekin Hesap uchun
tasdiq hisoblanmaydi. Shaxs imzolash paytida (MyID yoki E-IMZO) yoki Hesap'ga OneID bilan kirganda tasdiqlanadi./clients/{in}
CLIENTS_READMijoz Hesap'da bormi va shaxsi tasdiqlanganmi. Javob POST /clients bilan bir xil,
topilmasa 404.
/templates
TEMPLATES_READIlovaga ruxsat etilgan shablonlar. Javobdagi tasdiqlash turlari shartnoma qanday imzolanishini oldindan ko'rsatadi.
[
{
"id": "0f0c1f2e-8a41-4d02-9d55-2f7c1b6f9a30",
"nameUz": "Oldi-sotdi shartnomasi (muddatli to'lov)",
"nameRu": "Договор купли-продажи (рассрочка)",
"nameEn": "Sales contract (installments)",
"individualVerificationType": "OTP_SMS",
"legalVerificationType": "E_IMZO",
"productEnabled": true,
"productRequired": false,
"paymentScheduleEnabled": true,
"witnessCount": 0
}
]/templates/{templateId}/fields
TEMPLATES_READShablonning to'ldiriladigan maydonlari. Shartnomadagi values massivini shular bo'yicha
yig'asiz: har bir maydonning idsi templateFieldId ga, keyNamei
keyName ga tushadi.
/contracts
CONTRACTS_WRITEShablon asosida shartnoma tuzish. Shartnoma raqami avtomatik beriladi, holati — CREATED
(ikkala taraf imzosi kutiladi).
| Maydon | Turi | Izoh |
|---|---|---|
templateId majburiy | uuid | Ilovaga ruxsat etilgan shablon |
buyerIn, sellerIn | string | Taraflar. Bittasi ilova egasi bo'lishi kerak; bo'sh qolgani o'rniga ilova egasi qo'yiladi |
price | number | Shartnoma summasi |
currency | string | UZS / USD / RUB |
initialPayment | number | Boshlang'ich to'lov |
deliveryAt | datetime | Yetkazib berish sanasi |
values | array | Shablon maydonlari: { templateFieldId, keyName, value, position } |
payments | array | To'lov jadvali: { amount, paymentDate } |
products | array | Mahsulotlar (shablonda yoqilgan bo'lsa) |
witnessIds | array | Guvohlar (Hesap foydalanuvchi id'lari) |
{
"templateId": "0f0c1f2e-8a41-4d02-9d55-2f7c1b6f9a30",
"buyerIn": "31234567890123",
"price": 12500000,
"currency": "UZS",
"values": [
{ "templateFieldId": "7c1d0a55-3b21-4f88-9a0e-1d2b3c4d5e6f", "keyName": "product_name",
"value": "Samsung Galaxy S25", "position": 1 }
],
"payments": [
{ "amount": 4166667, "paymentDate": "2026-10-18T00:00:00Z" },
{ "amount": 4166667, "paymentDate": "2026-11-18T00:00:00Z" },
{ "amount": 4166666, "paymentDate": "2026-12-18T00:00:00Z" }
]
}{ "id": "9b3f7c21-55ad-4e10-8b6e-0c4a91f2d773" }/contracts/{id}
CONTRACTS_READShartnoma va uning holati. Asosiy maydonlar: status, buyerStatus,
sellerStatus, number, price, taraflar va values.
/contracts/{id}/pdf
CONTRACTS_READShartnoma PDF'i (application/pdf). Tilni ?lang=uz|ru|en bilan tanlang.
/contracts/{id}/sign-sessions
CONTRACTS_SIGNBitta tarafni imzolash uchun sessiya ochish. Har bir taraf uchun alohida sessiya oching.
| Maydon | Turi | Izoh |
|---|---|---|
signerIn majburiy | string | Kim imzolaydi — shartnomaning buyerIn yoki sellerIn qiymati |
lang | string | Iframe tili: uz (standart), ru, en |
parentOrigin | string | Iframe joylashadigan sayt, masalan https://shop.example.uz. Berilsa iframe'ni faqat shu sayt ko'rsata oladi va hodisalar faqat shu saytga yuboriladi. Production'da albatta bering. |
redirectUrl | string | Imzodan keyin «Davom etish» tugmasi ochadigan sahifa |
{
"id": "5b0f6c1e-4e7a-4a8b-9d7e-2f1c0a9b8d33",
"url": "https://sdk.hesap.uz/sign/Qx7fK2…",
"method": "OTP_SMS",
"expiresAt": "2026-09-18T11:19:02Z",
"status": "PENDING"
}urlfaqat shu javobda beriladi — Hesap tokenning o'zini saqlamaydi.- Sessiya 15 daqiqa amal qiladi va bir marta ishlatiladi: imzolangan yoki rad etilgandan keyin yopiladi. Muddati o'tsa, yangisini oching.
- Sessiya ochilmaydi, agar shartnoma
CREATEDholatida bo'lmasa, bu taraf allaqachon imzolagan bo'lsa yoki imzolovchi Hesap'da topilmasa (avvalPOST /clients).
/sign-sessions/{id}
CONTRACTS_SIGNSessiya holati: PENDING, SIGNED, REJECTED yoki EXPIRED.
Faqat o'z ilovangiz ochgan sessiyalar ko'rinadi.
Iframe
Sessiya javobidagi urlni sahifangizga joylang. Saytingiz HTTPS'da bo'lishi kerak.
<iframe
id="hesap-sign"
src="https://sdk.hesap.uz/sign/Qx7fK2…"
allow="camera"
style="width:100%; max-width:520px; height:640px; border:0">
</iframe>allow="camera" — MyID/AbleID bilan yuzni tasdiqlash uchun. Tasdiqlash yangi oynada ochiladi,
shuning uchun brauzerning popup blokerini hisobga oling.
Imzolash usullari
Usulni shablon belgilaydi, siz tanlamaysiz. Sessiya javobidagi method qaysi usul ekanini ko'rsatadi.
| method | Mijoz nima qiladi |
|---|---|
OTP_SMS | Telefoniga kelgan 5 xonali kodni kiritadi. 5 marta noto'g'ri kiritilsa sessiya yopiladi. |
MY_ID | Yangi oynada MyID orqali yuzini tasdiqlaydi. |
ABLE_ID | Yangi oynada AbleID orqali yuzini tasdiqlaydi. |
E_IMZO | Kompyuterdagi E-IMZO kaliti bilan imzolaydi. Yuridik shaxslar uchun odatiy usul. |
Iframe hodisalari
Iframe sahifangizga postMessage orqali xabar yuboradi. event.originni albatta tekshiring.
window.addEventListener("message", (event) => {
if (event.origin !== "https://sdk.hesap.uz") return;
const msg = event.data;
if (!msg || msg.source !== "hesap-sdk") return;
switch (msg.type) {
case "READY": /* oyna yuklandi; msg.method */ break;
case "RESIZE": document.getElementById("hesap-sign").style.height = msg.height + "px"; break;
case "SIGNED": /* imzolandi — serverda tekshiring */ break;
case "REJECTED": /* mijoz rad etdi */ break;
case "ERROR": /* sessiya yaroqsiz; msg.message */ break;
}
});| type | Qachon | Qo'shimcha maydonlar |
|---|---|---|
READY | Oyna yuklandi va shartnoma ko'rsatildi | method |
RESIZE | Oyna balandligi o'zgardi | height (px) |
SIGNED | Mijoz imzoladi | sessionId, contractId |
REJECTED | Mijoz rad etdi | |
ERROR | Sessiya yopilgan, muddati o'tgan yoki topilmadi |
GET /sign-sessions/{id} yoki GET /contracts/{id} bilan tekshiring yoki
webhook'ni kuting.Webhook
Ilovaga webhook manzili biriktirilgan bo'lsa, Hesap hodisalarni shu manzilga POST qiladi. Qaysi
hodisalarni olishni ilova yaratilganda belgilanadi; hech biri tanlanmasa hammasi keladi.
| Hodisa | Qachon |
|---|---|
CONTRACT_CREATED | Shartnoma tuzildi |
CONTRACT_SIGNED | Taraflardan biri imzoladi |
CONTRACT_ACTIVE | Ikkala taraf imzoladi — shartnoma kuchga kirdi |
CONTRACT_REJECTED | Taraf rad etdi |
CONTRACT_CANCELLED | Yaratuvchi bekor qildi |
PAYMENT_ACCEPTED | To'lov tasdiqlandi |
{
"event": "CONTRACT_SIGNED",
"contractId": "9b3f7c21-55ad-4e10-8b6e-0c4a91f2d773",
"contractNumber": "260918-0042",
"status": "CREATED",
"templateId": "0f0c1f2e-8a41-4d02-9d55-2f7c1b6f9a30",
"buyerIn": "31234567890123",
"sellerIn": "301234567",
"creatorIn": "301234567",
"actorIn": "31234567890123",
"amount": 12500000,
"currency": "UZS",
"occurredAt": "2026-09-18T11:06:41Z"
}| Header | Ma'nosi |
|---|---|
X-Hesap-Event | Hodisa turi |
X-Hesap-Delivery | Yetkazish id'si — bir hodisani ikki marta qayta ishlamaslik uchun saqlang |
X-Hesap-Signature | sha256=<hex> — tananing HMAC-SHA256 imzosi (webhook secret bilan; ilova yaratilganda beriladi) |
Imzoni tekshirish
Imzo xom tana ustidan hisoblanadi — JSON'ni parse qilishdan oldin tekshiring.
const crypto = require("crypto");
function verify(rawBody, signature, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
function verify($rawBody, $signature, $secret) {
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
return hash_equals($expected, $signature ?? '');
}
Javob 10 soniya ichida 2xx bo'lishi kerak. Aks holda Hesap 3 marta qayta urinadi, keyin hodisa
tashlab yuboriladi — muhim holatlarni vaqti-vaqti bilan GET /contracts/{id} orqali solishtirib turing.
Xatolar
| Kod | Sabab |
|---|---|
400 | Maydon noto'g'ri: PINFL 14 xonali emas, signerIn taraf emas, shartnoma CREATED holatida emas, SMS kodi noto'g'ri |
401 | Token yo'q, noto'g'ri yoki muddati tugagan — yangi token oling; /auth/token'da — appId yoki appSecret noto'g'ri |
403 | Huquq yetishmaydi, shablon ruxsat etilmagan, shartnoma ilova egasiga tegishli emas, ilova bekor qilingan; iframe'da — sessiya yopilgan yoki muddati o'tgan |
404 | Mijoz, shartnoma yoki sessiya topilmadi |
503 | Ichki xizmat vaqtincha javob bermadi — birozdan keyin qayta urining |
{
"code": 403,
"status": "403 Forbidden",
"message": "Bu shablon ilovaga ruxsat etilmagan",
"timestamp": "18 sentabr 2026 y., 16:04:02 UTC+5"
}Holatlar
| Maydon | Qiymatlar |
|---|---|
Shartnoma status | CREATED imzo kutilmoqda · ACTIVE kuchga kirdi · COMPLETED yakunlandi · REJECTED rad etildi · CANCELLED bekor qilindi |
buyerStatus, sellerStatus | PENDING · ACCEPTED · REJECTED |
Sessiya status | PENDING · SIGNED · REJECTED · EXPIRED |
Mijoz type | CLIENT jismoniy · COMPANY yuridik |
Ishga tushirishdan oldin
appSecretva token faqat serverda saqlanadi, brauzer yoki mobil ilova kodiga tushmaydi.- Token keshlanadi va 401 kelganda yangilanadi — har so'rov oldidan yangi token olinmaydi.
- Har bir sessiyaga
parentOriginberilgan. - Iframe hodisalarida
event.origintekshiriladi. - Buyurtma
SIGNEDxabari bilan emas, server tekshiruvi yoki webhook bilan tasdiqlanadi. - Webhook imzosi xom tana ustida tekshiriladi,
X-Hesap-Deliverytakrorlanishiga qarshi saqlanadi. - Muddati o'tgan sessiya uchun yangi sessiya ochish yo'li bor.