Dasturchilar uchun
API hujjatlari
Rozilik oling, har bir yuborishni tekshiring va bekor qilishlarga darhol javob bering. HTTPS orqali JSON, har bir integratsiyaga bitta Bearer kalit. Asosiy URL: https://<your-domain>/api
Ishni boshlash
Tezkor boshlash
Uch qadamda birinchi rozilikni oling va yuborishni tekshiring. Test kalitidan foydalaning: haqiqiy telefonlarga hech narsa yuborilmaydi.
Test API kalitini oling
Boshqaruv panelida API kalitlari bo‘limini oching, Test rejimiga o‘ting va verify hamda certificates:write ruxsatlari bilan kalit yarating. Kalitni faqat serveringizda saqlang.
export RZ_KEY=rz_test_…
export RZ_BASE=https://<your-domain>/apiRozilik oling
A variant, kod yozmasdan: har bir rozilik shablonining o‘z rozilik sahifasi bor. Uning havolasi yoki QR kodini Shablonlar bo‘limidan nusxalab, SMS orqali, chekda yoki kassada ulashing. Mijoz kanallarni belgilaydi, “Roziman” tugmasini bosadi va SMS-kodni tasdiqlaydi; sertifikatni biz beramiz.
https://<your-domain>/c/<public-id>B variant, o‘z formangiz: raqam va belgilangan kanallarni /v1/consents/otp manziliga yuboring, so‘ng mijoz kiritgan kodni bizga uzating. Batafsil: Rozilik olish (OTP).
C variant, o‘z formangiz, SMS-kodsiz: sahifaga skriptimizni qo‘shing: u tashrifni yozib oladi, serveringiz esa har bir lid uchun sertifikat rasmiylashtiradi. Batafsil: Veb-forma skripti.
Har bir yuborishdan oldin tekshiring
Har bir reklama xabaridan oldin SMS shlyuzingiz yoki CRM tizimingizdan Verify so‘rovini yuboring. Faqat allowed qiymati true bo‘lsa yuboring.
curl https://<your-domain>/api/v1/verify \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "+998901234567", "channel": "sms", "purpose": "promo" }'
{ "allowed": true, "reason": null, "certificate": "cert_01JB3M6Q8Z4X7N2K5R9T", ... }Ishni boshlash
Autentifikatsiya
Har bir /v1 so‘rovida kalitni Authorization sarlavhasida yuboring. Kalitlar rz_live_ yoki rz_test_ bilan boshlanadi, yaratilganda bir marta ko‘rsatiladi va ularni server IP manzillari ro‘yxati bilan cheklash mumkin.
Authorization: Bearer rz_live_…RUXSATLAR
verifyscope · ixtiyoriy | POST /v1/verify, /v1/verify/batch va /v1/campaigns/preflight |
|---|---|
certificates:writescope · ixtiyoriy | /v1/consents/otp yoki /v1/forms/claim orqali rozilik olish va /v1/revocations orqali bekor qilish |
customers:readscope · ixtiyoriy | O‘qish: /v1/customers va /v1/certificates/:id |
imports:writescope · ixtiyoriy | Mavjud mijozlar ro‘yxatini import qilish |
webhooks:managescope · ixtiyoriy | Webhook endpointlarini yaratish va ularning sirini yangilash |
Ishni boshlash
Test rejimi
Test kalitlari ishchi kalitlar kabi ishlaydi, faqat uchta farqi bor: SMS hech qachon yuborilmaydi (OTP test_code maydonida qaytadi), sertifikatlar "test": true bilan belgilanadi, test roziliklari esa ishchi kalitlarga ko‘rinmaydi (va aksincha). Test sertifikatlari ham xuddi shunday imzolanadi, shuning uchun imzo tekshiruvini ular ustida yozishingiz mumkin.
Asosiy API
Tekshirish
Har bir yuborishdan oldin bitta so‘rov. Biz mijozning tashkilotingizga bergan roziligini, kanalni, barcha jo‘natuvchilarga qo‘yilgan taqiqni va taqiqlangan vaqtni (Toshkent vaqti bilan 18:00–09:00) tekshiramiz hamda so‘raganingizga dalil sifatida tekshiruvni jurnalga yozamiz.
/v1/verifyruxsat verifySO‘ROV TANASI
phonestring · majburiy | O‘zbekiston mobil raqami, istalgan keng tarqalgan formatda: +998 90 123 45 67, 998901234567, 901234567. |
|---|---|
channel"sms" | "call" | "telegram" · majburiy | Mijoz bilan qaysi kanal orqali bog‘lanmoqchisiz. |
purpose"promo" | "transactional" · ixtiyoriy | Standart: promo. Xizmat xabarlariga har doim ruxsat beriladi, ular ham jurnalga yoziladi. |
send_atISO 8601, vaqt mintaqasi bilan · ixtiyoriy | Rejalashtirilgan yuborishlar uchun xabar ketadigan vaqt. Standart: hozir; taqiqlangan vaqt shunga qarab tekshiriladi. |
So‘rov
curl https://<your-domain>/api/v1/verify \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+998901234567",
"channel": "sms",
"purpose": "promo"
}'200 · ruxsat berildi
{
"allowed": true,
"reason": null,
"certificate": "cert_01JB3M6Q8Z4X7N2K5R9T",
"retry_after": null,
"checked_at": "2026-11-02T10:15:04.211Z",
"request_id": "req_01JB3N0Q2C7V9W4X6Y8Z"
}200 · taqiqlangan vaqt tufayli bloklandi
{
"allowed": false,
"reason": "QUIET_HOURS",
"certificate": "cert_01JB3M6Q8Z4X7N2K5R9T",
"retry_after": "2026-11-03T09:00:00+05:00",
"checked_at": "2026-11-02T14:30:00.000Z",
"request_id": "req_01JB3N7A1B3C5D7E9F0G"
}Bloklangan javob ham HTTP 200 bo‘ladi: reason maydonini o‘qing (qarang: sabab kodlari), taqiqlangan vaqtda esa yuborishni retry_after vaqtiga ko‘chiring. Noto‘g‘ri raqamga 422 invalid_phone qaytadi.
Asosiy API
Paketli tekshirish
Bitta so‘rovda 1000 tagacha tekshiruv, javoblar shu tartibda qaytadi. Noto‘g‘ri raqam butun paketni to‘xtatmaydi: xato faqat o‘sha qatorda qaytadi.
/v1/verify/batchruxsat verifySo‘rov
curl https://<your-domain>/api/v1/verify/batch \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{ "items": [
{ "phone": "+998901234567", "channel": "sms" },
{ "phone": "+998931112233", "channel": "sms" },
{ "phone": "12345", "channel": "sms" }
] }'200
{
"results": [
{ "phone": "+998901234567", "allowed": true, "reason": null, "certificate": "cert_01JB…", "retry_after": null, "checked_at": "…", "request_id": "req_…" },
{ "phone": "+998931112233", "allowed": false, "reason": "NO_CONSENT", "certificate": null, "retry_after": null, "checked_at": "…", "request_id": "req_…" },
{ "phone": "12345", "allowed": false, "reason": null, "certificate": null, "retry_after": null, "checked_at": "…", "request_id": "req_…",
"error": { "code": "invalid_phone", "message": "Not a valid Uzbek number. Use +998 and 9 digits." } }
]
}Asosiy API
Rozilik olish (OTP)
O‘z saytingiz yoki ilovangizdagi formada yig‘ilgan rozilik uchun. Biz mijozga SMS orqali 6 xonali kod yuboramiz (double opt-in); serveringiz kodni bizga uzatadi va sertifikat oladi. Kod 5 daqiqa amal qiladi, 3 ta urinish beriladi.
/v1/consents/otpruxsat certificates:writeSO‘ROV TANASI
templatestring · majburiy | Boshqaruv panelidagi shablon kaliti, masalan promo_sms. Mijozga ko‘rsatilgan matn shu shablonning faol versiyasi bo‘lishi shart. |
|---|---|
phonestring · majburiy | Mijozning raqami. |
channelsstring[] · majburiy | Faqat mijoz belgilagan va shablonda bor kanallar. |
locale"uz" | "ru" | "en" · ixtiyoriy | Mijoz ko‘rgan matn tili. Standart: uz. |
evidenceobject · ixtiyoriy | events ({ type, at } massivi), pageUrl, referrer, screen. Sertifikatga yoziladi. |
ip, user_agentstring · ixtiyoriy | Serveringiz ko‘rgan mijoz IP manzili va brauzeri. IP faqat xesh ko‘rinishida saqlanadi. |
Boshlash
curl https://<your-domain>/api/v1/consents/otp \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "promo_sms",
"phone": "+998901234567",
"channels": ["sms"],
"locale": "uz",
"evidence": {
"events": [
{ "type": "page_opened", "at": "2026-11-02T10:14:31.020Z" },
{ "type": "channel_ticked:sms", "at": "2026-11-02T10:14:39.551Z" },
{ "type": "agree_tapped", "at": "2026-11-02T10:14:42.108Z" }
],
"pageUrl": "https://shop.example.uz/signup"
},
"ip": "203.0.113.24",
"user_agent": "Mozilla/5.0 …"
}'
{ "session": "cs_01JB3P2K…", "expires_at": "2026-11-02T10:19:42.300Z", "test_code": "481902" }/v1/consents/otp/{session}/confirmruxsat certificates:writeTasdiqlash
curl https://<your-domain>/api/v1/consents/otp/cs_01JB3P2K…/confirm \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{ "code": "481902" }'
{ "certificate": "cert_01JB3P3M…", "verify_url": "https://<your-domain>/cert/cert_01JB3P3M…" }test_code faqat test kalitlari uchun qaytariladi. Noto‘g‘ri kodga details.attemptsLeft bilan code_invalid javobi keladi; qarang: xatolar.
Asosiy API
Veb-forma skripti
Mavjud formalaringiz o‘z holicha qoladi. Bitta script tegi sahifaga har bir tashrifni yozib oladi, lid kelganda esa serveringiz yozuvni imzolangan sertifikatga aylantiradi: biz raqam aynan shu formada kiritilganini, rozilik matningiz sahifada bo‘lganini va belgini mijozning o‘zi qo‘yganini tekshiramiz. SMS-kod ham, formaning ko‘rinishini o‘zgartirish ham kerak emas.
Skriptni qo‘shing
Uni forma bor har bir sahifaga bir marta, HTML ichida istalgan joyga qo‘ying.
<script src="https://<your-domain>/f.js" async></script>Formani belgilang
Shabloningizning joriy matnini sahifada so‘zma-so‘z ko‘rsating (solishtirishda bo‘shliqlar, harf registri va apostroflar normallashtiriladi; matnni GET /v1/templates/{key} yoki boshqaruv panelidan oling). Uchta ixtiyoriy atribut skriptga qaysi element nima ekanini bildiradi:
| data-rozilik="phone" | Telefon raqami maydoni. Atribut bo‘lmasa, skript input[type=tel] ni yoki nomida phone, tel, telefon so‘zi bor maydonni oladi. |
|---|---|
| data-rozilik="opt-in" | Rozilik belgisi (checkbox). Sahifa ochilganda u bo‘sh turishi kerak. Belgi bo‘lmasa, formani yuborishning o‘zi rozilik hisoblanadi. |
| data-rozilik="consent" | Rozilik matni joylashgan element. U bo‘lmasa, skript rozilik belgisining label matnini o‘qiydi. |
| <script data-field="…"> | Yashirin maydon uchun boshqa nom. Standart: rozilik_cert_url. |
Misol
<script src="https://<your-domain>/f.js" async></script>
<form action="/lead" method="post">
<input type="tel" name="phone" data-rozilik="phone" placeholder="+998 90 123 45 67" required>
<label>
<input type="checkbox" name="consent" data-rozilik="opt-in">
<span data-rozilik="consent">Men Savdo Market MChJdan aksiya va takliflar haqida SMS xabarlar olishga roziman. Roziligimni istalgan vaqtda STOP deb javob berib bekor qilishim mumkin.</span>
</label>
<button type="submit">Yuborish</button>
<!-- f.js adds <input type="hidden" name="rozilik_cert_url" value="…/f/fs_…"> -->
</form>Mijoz formani to‘ldiradi
Skript tashrifni kiritilgan qiymatlarni yashirgan holda yozib oladi va sertifikat URL manzilini (https://…/f/fs_…) har bir formadagi yashirin rozilik_cert_url maydoniga qo‘yadi. Formangiz uni lidning boshqa ma’lumotlari bilan birga serveringizga yuboradi.
Sertifikatni serverdan rasmiylashtiring
Sertifikat URL manzilini, mijoz kiritgan raqamni va shablon kalitini yuboring. Manbasi web_snippet bo‘lgan, ichida yozuv xeshi muhrlangan sertifikat olasiz. 72 soat ichida rasmiylashtiring.
/v1/forms/claimruxsat certificates:writeSO‘ROV TANASI
cert_urlstring · majburiy | Formadagi rozilik_cert_url qiymati yoki shunchaki fs_… id. |
|---|---|
phonestring · majburiy | Mijoz formaga kiritgan raqam. |
templatestring · majburiy | Matni sahifada turgan shablon kaliti, masalan promo_sms. |
channelsstring[] · ixtiyoriy | Standart: shablondagi barcha kanallar. |
referencestring · ixtiyoriy | Lid yoki buyurtmangiz identifikatori, audit jurnalida saqlanadi. |
curl
curl -X POST https://<your-domain>/api/v1/forms/claim \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{
"cert_url": "<value of rozilik_cert_url from the form>",
"phone": "+998901234567",
"template": "promo_sms"
}'Node.js
// In your form handler, after you save the lead
const res = await fetch('https://<your-domain>/api/v1/forms/claim', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.RZ_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
cert_url: req.body.rozilik_cert_url,
phone: req.body.phone,
template: 'promo_sms',
reference: lead.id, // optional, kept in the audit log
}),
});
const claim = await res.json();
if (!res.ok) throw new Error(claim.error.code); // e.g. opt_in_not_ticked
await saveCertificate(lead.id, claim.certificate);200
{
"certificate": "cert_01JB3M6Q8Z4X7N2K5R9T",
"verify_url": "https://<your-domain>/cert/cert_01JB3M6Q8Z4X7N2K5R9T",
"form_session": "fs_01JB3M5V…",
"test": false,
"checks": {
"phone_matched": true,
"consent_language": { "found": true, "locale": "uz" },
"opt_in": "user_ticked",
"submitted": true
},
"page_url": "https://shop.example.uz/signup",
"recorded_at": "2026-11-02T10:14:31.020Z",
"duration_ms": 48210
}Xuddi shu kalit, raqam va yozuv bilan qayta rasmiylashtirish o‘sha sertifikatni qaytaradi, shuning uchun qayta urinish xavfsiz. Bitta yozuvni bir nechta kompaniya rasmiylashtirishi mumkin (masalan, lid xaridori); har biri o‘z sertifikatini oladi. Tekshiruvlar quyidagi tartibda bajariladi va birinchi o‘tmagan tekshiruv javob qaytaradi:
| code | HTTP | Ma’nosi |
|---|---|---|
| form_session_not_found | 404 | Bu sertifikat URL yoki fs_… id bilan yozuv topilmadi. Yashirin maydon serveringizga yetib kelayotganini tekshiring. |
| form_session_expired | 410 | Yozuv o‘z vaqtida rasmiylashtirilmagan va o‘chirilgan. Forma yuborilishi bilan rasmiylashtiring. |
| template_not_found | 404 | Tashkilotingizda bunday kalitli shablon yo‘q. |
| channels_not_in_template | 422 | Shablonda yo‘q kanallar so‘ralgan. |
| phone_not_in_form | 422 | Bu raqam ushbu yozuvda kiritilmagan. Mijoz kiritgan raqamni yuboring. |
| consent_language_not_found | 422 | Shablon matni sahifada topilmadi. Uning joriy matnini sahifaga so‘zma-so‘z joylang. |
| opt_in_pre_ticked | 422 | Sahifa ochilganda rozilik belgisi allaqachon qo‘yilgan edi. Uni bo‘sh qoldiring: belgini mijozning o‘zi qo‘yishi kerak. |
| opt_in_not_ticked | 422 | Sahifada rozilik belgisi bor, lekin mijoz uni belgilamagan. |
Maxfiylik
- Yozuvda kiritilgan qiymatlar yashiriladi: unda maydon to‘ldirilgani ko‘rinadi, nima yozilgani emas.
- Telefon raqamlari kalitli xesh orqali solishtiriladi. Yozuvdagi raqamni hech qachon ochiq matnda saqlamaymiz.
- Hech kim rasmiylashtirmagan yozuvlar 72 soatdan keyin o‘chiriladi.
- Rasmiylashtirilgan yozuvni faqat uni rasmiylashtirgan kompaniya, regulyatorlar va shu kompaniya ulashgan havolaga ega bo‘lganlar ko‘ra oladi. Sertifikat sahifasida yozuv emas, tekshiruvlar ko‘rsatiladi.
Asosiy API
Sertifikatlar
Sertifikatlaringizdan birini o‘qing: imzolangan payload, uning SHA-256 xeshi, ES256 imzosi va rozilikning joriy holati. Xuddi shu hujjat /public/certificates/:id manzilida ochiq va /cert/:id sahifasida ko‘rinadi.
/v1/certificates/{id}ruxsat customers:read200
{
"id": "cert_01JB3M6Q8Z4X7N2K5R9T",
"status": "active",
"issuedAt": "2026-11-01T04:41:12.000Z",
"revokedAt": null,
"sender": { "legalName": "Savdo Market MChJ", "tin": "301234567" },
"phoneMasked": "+998 •• ••• •• 67",
"channels": ["sms"],
"purposes": ["promo"],
"source": "hosted_page",
"locale": "uz",
"text": "Men … roziman …",
"templateVersion": 3,
"payload": { "v": 1, "id": "cert_01JB3M6Q8Z4X7N2K5R9T", "issuer": "RozilikID", … },
"payloadSha256": "9f2c…",
"signature": "MEUCIQ…",
"keyId": "rz-2026-10",
"alg": "ES256",
"test": false
}Asosiy API
Mijozlar
Bitta raqamning barcha shablonlaringiz bo‘yicha joriy rozilik holati, eng yangisi birinchi.
/v1/customers?phone={phone}ruxsat customers:readSo‘rov
curl "https://<your-domain>/api/v1/customers?phone=%2B998901234567" \
-H "Authorization: Bearer $RZ_KEY"200
{
"phone": "+998901234567",
"consents": [
{
"certificate": "cert_01JB3M6Q8Z4X7N2K5R9T",
"status": "active",
"channels": ["sms", "telegram"],
"template": "promo_sms",
"consented_at": "2026-11-01T04:41:12.000Z",
"expires_at": "2028-11-01T04:41:12.000Z"
}
]
}Asosiy API
Rozilikni bekor qilish
RozilikID orqali emas, boshqa yo‘l bilan kelgan bekor qilish so‘rovini qayd eting, masalan, mijoz call-markazingizga xabarlarni to‘xtatishni so‘rab murojaat qilgan bo‘lsa. Barcha kanallarni bekor qilish uchun channels maydonini yubormang.
/v1/revocationsruxsat certificates:writeSO‘ROV TANASI
phonestring · majburiy | Mijozning raqami. |
|---|---|
viastring · ixtiyoriy | So‘rov qayerdan kelgani: api (standart), call_center, operator, unsubscribe_link, … |
channelsstring[] · ixtiyoriy | Faqat shu kanallar bo‘yicha bekor qilish. |
curl https://<your-domain>/api/v1/revocations \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "+998901234567", "via": "call_center" }'
{ "revoked": 1 }Asosiy API
Kampaniya tekshiruvi
Kampaniyadan oldin butun ro‘yxatni tekshiring. Javobda xabar yuborish mumkin bo‘lgan raqamlar va chiqarib tashlangan har bir raqam sababi bilan qaytadi. Bitta so‘rovda 100 000 tagacha raqam.
/v1/campaigns/preflightruxsat verifySo‘rov
curl https://<your-domain>/api/v1/campaigns/preflight \
-H "Authorization: Bearer $RZ_KEY" \
-H "Content-Type: application/json" \
-d '{
"phones": ["+998901234567", "+998931112233", "+998977654321"],
"channel": "sms",
"purpose": "promo",
"send_at": "2026-11-03T10:00:00+05:00"
}'200
{
"total": 3,
"allowed": ["+998901234567"],
"removed": [
{ "phone": "+998931112233", "reason": "NO_CONSENT" },
{ "phone": "+998977654321", "reason": "REVOKED" }
]
}Qo‘shimcha
Webhooklar
API kalitlari → Webhooklar bo‘limida endpoint qo‘shing va hodisalarni tanlang. Biz JSON ma’lumotni POST so‘rovida quyidagi sarlavhalar bilan yuboramiz: X-Rozilik-Signature, X-Rozilik-Event va X-Rozilik-Delivery (har bir yetkazishda yagona; dublikatlarni o‘tkazib yuborish uchun ishlating). Istalgan 2xx bilan javob bering. Yetkazilmagan so‘rovlar 1 daqiqa, 5 daqiqa, 30 daqiqa, 2 soat va 12 soatdan keyin qayta yuboriladi.
| Hodisa | Qachon | data |
|---|---|---|
| consent.created | Mijoz rozilikni tasdiqladi va sertifikat berildi. | certificate, phone_last4, channels, purposes, template, source, consented_at |
| consent.revoked | Mijoz roziligini bekor qildi: STOP javobi, Telegram bot, boshqaruv paneli yoki API orqali. Yuborishni darhol to‘xtating. | certificate, phone_last4, via, channels, revoked_at |
| consent.expiring | Rozilikni saqlash muddati tugashiga oz qoldi. Qayta rozilik so‘rovini yuboring. | certificate, phone_last4 va tugash vaqti |
| campaign.checked | Boshqaruv panelida kampaniya tekshiruvi yakunlandi. | campaign, name, status, channel, purpose, send_at, total, allowed, removed, by_reason |
So‘rov tanasi
{
"id": "evt_01JB3Q8W…",
"type": "consent.revoked",
"created_at": "2026-11-02T12:03:44.120Z",
"livemode": true,
"data": {
"certificate": "cert_01JB3M6Q8Z4X7N2K5R9T",
"phone_last4": "4567",
"via": "telegram",
"channels": ["sms"],
"revoked_at": "2026-11-02T12:03:44.090Z"
}
}Imzo sarlavhasi t=<unix seconds>,v1=<hex> ko‘rinishida bo‘ladi: v1 — `${t}.${rawBody}` satrining endpoint maxfiy kaliti bilan hisoblangan HMAC-SHA256 qiymati. Imzoni JSON parse qilinishidan oldin, xom baytlar bo‘yicha tekshiring:
Node.js (Express)
import crypto from 'node:crypto';
import express from 'express';
const app = express();
app.post('/webhooks/rozilik', express.raw({ type: 'application/json' }), (req, res) => {
const header = req.get('X-Rozilik-Signature') ?? '';
const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')));
const t = Number(parts.t);
const expected = crypto
.createHmac('sha256', process.env.RZ_WEBHOOK_SECRET)
.update(`${t}.${req.body}`) // req.body is the raw Buffer
.digest('hex');
const valid =
typeof parts.v1 === 'string' &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected)) &&
Math.abs(Date.now() / 1000 - t) < 300; // reject replays older than 5 minutes
if (!valid) return res.status(400).send('invalid signature');
const event = JSON.parse(req.body.toString('utf8'));
if (event.type === 'consent.revoked') {
// Stop messaging this customer now: event.data.certificate
}
res.sendStatus(200);
});Qo‘shimcha
Sertifikatni tekshirish
Har kim sertifikatni RozilikID so‘ziga ishonmasdan tekshira oladi: uni yuklab oling, payload maydonini kanonik ko‘rinishga keltiring (kalitlar saralangan, bo‘shliqlarsiz), uning SHA-256 xeshini payloadSha256 bilan solishtiring va ES256 imzosini /.well-known/jwks.json manzilidagi ochiq kalitimiz bilan tekshiring. /cert/:id sertifikat sahifasi brauzerda aynan shuni bajaradi.
Node.js 20+
import { createHash, webcrypto } from 'node:crypto';
const canonicalize = (v) =>
v === null || typeof v !== 'object'
? JSON.stringify(v)
: Array.isArray(v)
? '[' + v.map((x) => (x === undefined ? 'null' : canonicalize(x))).join(',') + ']'
: '{' + Object.keys(v).filter((k) => v[k] !== undefined).sort()
.map((k) => JSON.stringify(k) + ':' + canonicalize(v[k])).join(',') + '}';
const id = 'cert_01JB3M6Q8Z4X7N2K5R9T';
const cert = await (await fetch(`https://<your-domain>/api/public/certificates/${id}`)).json();
const { keys } = await (await fetch('https://<your-domain>/.well-known/jwks.json')).json();
const jwk = keys.find((k) => k.kid === cert.keyId);
const bytes = new TextEncoder().encode(canonicalize(cert.payload));
const hashOk = createHash('sha256').update(bytes).digest('hex') === cert.payloadSha256;
const key = await webcrypto.subtle.importKey('jwk', jwk, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);
const signatureOk = await webcrypto.subtle.verify(
{ name: 'ECDSA', hash: 'SHA-256' }, key, Buffer.from(cert.signature, 'base64url'), bytes,
);
console.log({ hashOk, signatureOk });Qo‘shimcha
Sabab kodlari
allowed false bo‘lganda reason maydonida qaytadi (xizmat xabariga ruxsat berilganda esa TRANSACTIONAL). INVALID_PHONE faqat kampaniya tekshiruvi natijalarida uchraydi.
| Kod | Ma’nosi | Nima qilish kerak |
|---|---|---|
| TRANSACTIONAL | Xizmat xabari. Xizmat xabarlari uchun reklama roziligi talab qilinmaydi. Tekshiruv baribir qayd etiladi. | Yuboring. Reklama mazmunini qo‘shmang. |
| GLOBAL_DND | Barcha jo‘natuvchilar to‘xtatilgan. Mijoz barcha jo‘natuvchilardan keladigan reklama xabarlarini to‘xtatgan. | Yubormang. |
| QUIET_HOURS | Taqiqlangan vaqt. Toshkent vaqti bilan 18:00 dan 09:00 gacha reklama yuborish taqiqlangan. | 09:00 dan keyinga rejalashtiring. |
| NO_CONSENT | Rozilik yo‘q. Bu jo‘natuvchida ushbu raqam uchun amaldagi sertifikat yo‘q. | Avval rozilik oling. |
| REVOKED | Rozilik bekor qilingan. Mijoz roziligini bekor qilgan. | Yubormang. Ro‘yxatdan olib tashlang. |
| EXPIRED | Rozilik muddati tugagan. Rozilik shablonda belgilangan muddatdan eskirgan. | Qayta rozilik so‘rovini yuboring. |
| WRONG_CHANNEL | Boshqa kanal. Rozilik boshqa kanal uchun berilgan. | Shu kanal uchun rozilik so‘rang. |
| INVALID_PHONE | Noto‘g‘ri raqam. Bu O‘zbekiston raqami emas (+998 va 9 ta raqam bo‘lishi kerak). | Raqamni tuzating. |
Qo‘shimcha
Xatolar va limitlar
Barcha xatolar bir xil tuzilishda. Mantiqni code bo‘yicha quring, odamlarga esa message matnini ko‘rsating.
HTTP/1.1 403 Forbidden
{
"error": {
"code": "forbidden",
"message": "This key lacks the \"verify\" permission"
}
}| code | HTTP | Ma’nosi |
|---|---|---|
| validation_failed | 400 | So‘rov tanasi yoki query parametrlari sxemaga mos emas. details har bir muammoni sanab beradi. |
| invalid_api_key | 401 | Kalit yuborilmagan, noma’lum yoki bekor qilingan. |
| forbidden | 403 | Kalitda bu endpoint uchun ruxsat yo‘q yoki so‘rov kelgan IP kalitning ruxsat etilgan ro‘yxatida emas. |
| not_found | 404 | Sertifikat, sessiya yoki resurs tashkilotingizda mavjud emas. |
| invalid_phone | 422 | Faqat POST /v1/verify uchun: raqam O‘zbekiston mobil raqami emas (+998 va 9 ta raqam). |
| code_invalid | 400 | Noto‘g‘ri OTP. details.attemptsLeft nechta urinish qolganini ko‘rsatadi. |
| code_expired | 410 | OTP 5 daqiqadan eski. Yangi sessiya boshlang. |
| too_many_attempts | 429 | Uch marta noto‘g‘ri kod kiritildi. Sessiya yopildi. |
| too_many_sessions | 429 | Bitta raqam uchun bir soatda 5 tadan ortiq rozilik sessiyasi. |
| rate_limited | 429 | So‘rovlar juda ko‘p. Biroz kutib, qayta urining. |
| internal_error | 500 | Xato bizning tomonda. Oraliqni oshirib qayta urining; request_id qo‘llab-quvvatlash xizmatiga yordam beradi. |
- Standart holatda har bir API klienti uchun daqiqasiga 600 ta so‘rov; ochiq rozilik endpointlarida limit qattiqroq.
- Paketli tekshirish: 1000 tagacha element. Kampaniya tekshiruvi: 100 000 tagacha raqam.
- OTP: 5 daqiqa amal qiladi, 3 ta urinish, yangi kod 60 soniyadan keyin, bitta raqamga soatiga ko‘pi bilan 5 ta sessiya.
- Reklama yuborish Toshkent vaqti bilan (UTC+5) 18:00–09:00 oralig‘ida, rozilikdan qat’i nazar, bloklanadi.