OpenAPI 3.1REST · v1
Dona API
Doʻkoningizni oʻz tizimingizga ulang: mahsulotlar, zaxira va narxlar, buyurtmalar, hisob holati va hodisalar — bitta REST API orqali. 1C, MoySklad, BILLZ, SmartUp, Linko va AI-agentlar uchun.
Kalitni doʻkon egasi sotuvchi kabinetida yaratadi: Sozlamalar › API. Kalit faqat bir marta koʻrsatiladi.
- Asosiy manzil
https://api.dona.im/seller-api/v1- Kalit turlari
dona_sk_live_…integratsiya kaliti — ERP, 1C, POS va oʻz tizimingiz uchundona_ak_live_…AI-agent kaliti — faqat MCP orqalidona_it_live_…dastur oʻrnatish tokeni — tez orada
API bosqichma-bosqich ochilmoqda. Qaysi qismlar hozir ishlayotganini «Holat» sahifasi, nima qoʻshilganini «Oʻzgarishlar» koʻrsatadi.
/mecurl -sS https://api.dona.im/seller-api/v1/me \
-H "Authorization: Bearer $DONA_KEY"{
"key": { … },
"shop": { … },
"tier": "basic",
"api_access": { … },
"writes_enabled": false,
"limits": {
"requests_per_min": 300,
"burst": 60,
"requests_per_day": 100000,
"writes_per_min": 60,
"writes_per_day": 20000,
"in_flight": 4,
"seller_requests_per_min": 900,
"remaining": { … }
},
"attention": { … },
"docs_url": "https://dona.uz/uz/developers"
}Mundarija
0108
Tezkor boshlash
4 qadamToʻrt qadam: kalit, birinchi soʻrov, xavfsiz sinov yozuvi va hodisalar oqimi.
Kalit yarating
Sotuvchi kabineti › Sozlamalar › API › Yangi kalit yaratish. Faqat kerakli ruxsatlarni (scope) belgilang. Birinchi kalitni yaratishdan oldin doʻkon egasi sotuvchi kabinetida 2-ilova (API va avtomatlashtirilgan kirish) shartlarini qabul qilishi shart.
Doʻkon egasi amaldagi 2-ilovani qabul qilmaguncha har bir kirish yoʻli — REST, MCP va OAuth — 403 agreement_required javobini
accept_urlbilan qaytaradi: bu ilova qabul qilinadigan kabinet sahifasi.Kim ekaningizni tekshiring
GET /mekalit, doʻkon, daraja (Asosiy/Kengaytirilgan), ruxsatlar va joriy chegaralarni qaytaradi.GET /me curl -sS https://api.dona.im/seller-api/v1/me \ -H "Authorization: Bearer $DONA_KEY"GET /mejavobi (spetsifikatsiyadagi misol)200 { "key": { "id": "0199760c-2f4b-7a3e-9d21-5c8e4b1f0a37", "name": "billz-prod", "kind": "sk", "prefix": "dona_sk_live_3fK", "scopes": [ "catalog:read", "catalog:stock", "orders:read" ], "expires_at": "2027-09-24T00:00:00+05:00", "ip_allow": [] }, "shop": { "id": "0198f3a2-6c1d-7b40-8e55-2a9c3d4e5f60", "name": "Bahor Textile", "status": "approved", "documents_status": "approved", "kyc_status": "approved", "can_sell": true }, "tier": "basic", "api_access": { "state": "enabled", "reason": null }, "writes_enabled": false, "limits": { "requests_per_min": 300, "burst": 60, "requests_per_day": 100000, "writes_per_min": 60, "writes_per_day": 20000, "in_flight": 4, "seller_requests_per_min": 900, "remaining": { "requests_per_min": 287, "requests_per_day": 99412, "writes_per_min": 60, "writes_per_day": 20000 } }, "attention": { "open": 3, "action_required": 2 }, "docs_url": "https://dona.uz/uz/developers" }Zaxirani sinab yozing
Dona-Dry-Run: truebilan har bir yozuv tekshiriladi, natija hisoblanadi va hech narsa saqlanmaydi.Yozuvlar hali yopiq boʻlsa (
writes_enabled), server503 limits_unavailableqaytaradi — bu kalit xatosi emas.POST /stock curl -sS -X POST https://api.dona.im/seller-api/v1/stock \ -H "Authorization: Bearer $DONA_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Dona-Dry-Run: true" \ -H "Content-Type: application/json" \ -d '{"items":[{"seller_sku":"A-100","quantity":12}]}'Oʻzgarishlarni oling
GET /events?cursor=…— asosiy kanal. Webhooklar shu hodisalarni sizga yuboradi.GET /events curl -sS "https://api.dona.im/seller-api/v1/events?cursor=$LAST_EVENT_ID&limit=200" \ -H "Authorization: Bearer $DONA_KEY"
0208
Maʼlumotnoma
14 guruh · 61 amalHar bir amal OpenAPI shartnomasidan sayt yigʻilayotganda chizilgan. Belgi amalga qaysi darajadagi kalit va qaysi ruxsat kerakligini koʻrsatadi.
Maʼlumotnoma shartnomaning oʻzi kabi ingliz tilida.
- Asosiy
- Har qanday amaldagi kalit
- Kengaytirilgan
- Shaxs, hujjatlar va doʻkon tasdiqlangan, jazo yoʻq
- Ochiq
- Kalitsiz
Umumiy parametrlar (har bir amalda nomi bilan koʻrsatilgan)11
Idempotency-Keyheader · string1–255 chars. Scope = this key × route. Terminal 2xx/4xx replayed byte-identical for 24 h; a 5xx is never stored. Missing ⇒
400 invalid_bodywithdetails[{field:"Idempotency-Key",code:"required"}].Accept-Languageheader · stringLocalises
messagein error bodies and single-language renderings. Defaultuz.X-Dona-Integrationheader · stringname/versionof the calling integration; stored (≤ 128 chars) and searchable in the request journal.Dona-Dry-Runheader · stringtrue⇒ validate + guard + compute the effect, then roll back. Zero side-effect rows (no events, no activity, no counters). Same as?dry_run=true. Only the literaltrue/false; any other value ⇒400 invalid_body+details[{field:"Dona-Dry-Run", code:"invalid"}](C51).dry_runquery · stringAlias of the
Dona-Dry-Runheader. Only the literal stringstrue/false—1,0,TRUE,yes, an empty value ⇒400 invalid_body+details[{field:"dry_run", code:"invalid"}](C51). A string enum, not a boolean, so no SDK generator serialises it as1/0.Dona-Sellerheader · string (uuid)Vendor-app install keys only (
dona_it_live_…, S6) — and then REQUIRED on every request, public routes included: the id of the shop the install key belongs to. Missing ⇒400 invalid_body+details[{field:"Dona-Seller", code:"required"}]; sent more than once, or not ONE id in the canonical form the API prints (lower-case, 36 characters — no braces, nourn:uuid:, no padding) ⇒400 invalid_body+details[{field:"Dona-Seller", code:"invalid"}]; naming any other shop — even one that installed the same app ⇒404 not_found(never 403; nothing is read). Ignored on a seller key (dona_sk_).If-None-Matchheader · stringAn
ETagfrom a previous identical request ⇒304with rate headers (cost 0.5).cursorquery · stringOpaque keyset cursor from
next_cursor.limitquery · integerPage size, default 50, max 100 (clamped, with
Dona-API-Warn).limit > 50costs1 + ceil(limit/50).updated_sincequery · stringISO 8601 with offset, or epoch milliseconds. The visible high-water mark is capped at
now() − 10 sso a slow transaction is never skipped.pagequery · integer0-based page alias (Uzum parity) — slower than
cursor, ≤ 1 000 pages; mutually exclusive withcursor.
0308
Chegaralar
Chegaralar IP boʻyicha emas, tasdiqlangan kalit va doʻkon boʻyicha hisoblanadi. Quyida standart qiymatlar; kalitingizga amal qiladiganlari GET /me → limits da.
| Chegara | Asosiy sk | Kengaytirilgan sk | Agent ak |
|---|---|---|---|
| Soʻrov / daqiqa (kalit) | 300 · burst 60 | 600 · burst 120 | 60 · burst 20 |
| Soʻrov / kun (kalit) | 100 000 | 250 000 | 20 000 |
| Yozuv / daqiqa | 60 | 120 | 10 |
| Yozuv / kun | 20 000 | 50 000 | 2 000 |
| Bir vaqtdagi soʻrovlar | 4 | 8 | 4 |
| Soʻrov / daqiqa (doʻkon, barcha kalitlar) | 900 | 1 800 | — |
- Bitta mahsulot zaxirasi yoki narxi — 10 soniyada 1 yozuv (
object_cooldown). - Ommaviy yozuv ≤ 1 000 qator; tana ≤ 256 KiB (ommaviy — 4 MiB). Tavsiya: 100–300 qator.
- Sahifa
limit≤ 100 (/eventsda ≤ 200).If-None-Match→304yarim narx. - Bizning 429/503 va 5xx javoblar hisobga olinmaydi va kalitni toʻxtatmaydi.
Dona-Rate-Limited-Reason qiymatlari:
key-ratewrite-rateseller-rateconcurrencyobject-cooldownapp-rateglobalsuspended
0408
Xato kodlari
59 kodHar bir xato bir xil konvert: error — barqaror kod, message — Accept-Language boʻyicha tarjima.
Kod boʻyicha tarmoqlang, hech qachon message boʻyicha emas.
{
"error": "insufficient_scope",
"message": "Bu amal uchun ruxsat yetarli emas.",
"request_id": "req_01997b2e-9a8b-7c6d-8e5f-4a3b2c1d0e9f",
"details": [],
"doc_url": "https://dona.uz/uz/developers/errors#insufficient_scope",
"required_scope": "orders:write"
}202Accepted
approval_requiredthe MCP door — see MCP
400Bad Request
invalid_bodymalformed JSON, a missing
Idempotency-Key, validation (details[]carries field codes such asikpu_required,cursor_expired), adry_run/Dona-Dry-Runthat is not the literaltrue/false(details[{field, code:"invalid"}], C51), a vendor-app install key withoutDona-Seller(details[{field:"Dona-Seller", code:"required"}], S6) or with a repeated / non-canonical one (code:"invalid"), or an op-specific 400 (invalid_decline_reason)invalid_decline_reasonrequest_state_invalidthe MCP door — see MCP
401Unauthorized
api_key_malformedchecksum fails — refused before any DB read
api_key_expired+
rotate_url, no graceapi_key_revokedalso a vendor-app key whose install was uninstalled — S6
key_kind_not_acceptedan agent key
akon this treedownload_token_invaliddownload_token_expiredinvalid_tokenthe MCP door — see MCP
Shuningdek a seller/app/staff JWT on this tree
403Forbidden
insufficient_scope+
required_scope; also a scope indisabled_scopestier_required+
scope; derived on every request; also a key minted for a third-partyorders:piirecipient —details[pii_recipient: pii_third_party_pending_counsel], D7, C59key_suspended+
suspended_until,Retry-After,Dona-Rate-Limited-Reason: suspendedapi_blockedip_not_allowedjudged on the trusted client IP only
seller_not_approvedshop closed/blocked/suspended/restricted
not_a_sellernever on this tree; the portal's owner doors
app_frozenS6: every key of a frozen vendor app, from the next request
agreement_required+
accept_url: the shop owner has not accepted the CURRENT Annex 2 «API and automated access» — the version in force or, while none is, the earliest announced; accepted once in Settings › API, then every door admits the key again. Checked after the sanctions, before the scopesrequest_state_foreignthe MCP door — see MCP
404Not Found
not_foundevery missing OR foreign id (never 403: no existence oracle)
409Conflict
idempotency_in_progress+
Retry-After: 2idempotency_mismatchversion_conflictai_review_openpublish of a product whose Dona AI review case is open — the review decides its status
order_not_acceptableno_pickup_addressorder_not_shippableorder_awaiting_courierorder_not_cancellableorder_has_active_returnno_tracking_number+
ordersno_items_selectedall_items_delayedS4, C53
confirmation_declinednothing written · the MCP door — see MCP
request_state_mismatchthe MCP door — see MCP
request_state_replayedthe MCP door — see MCP
held_write_not_pendingan intent's fate · the MCP door — see MCP
Shuningdek a replay of a rejected held write
410Gone
request_state_expiredthe MCP door — see MCP
hold_expiredan intent's fate · the MCP door — see MCP
413Content Too Large
payload_too_largebody > 256 KiB (4 MiB on bulk stock/prices/batch), or > 1 000 lines
422Unprocessable Content
webhook_url_invalid+
details[].code∈timeout,status_<n>,tls,dns,private_address,schemewarehouse_unsupported
429Too Many Requests
rate_limitedwith
Dona-Rate-Limited-Reason: app-rate: a vendor app's bucket, shared by all its installs — S6write_rate_limitedconcurrency_limitedseller_rate_limitedobject_cooldownapi_busyintent_limitthe MCP door — see MCP
Shuningdek Always a JSON body + Retry-After from the origin (an edge 429 from Cloudflare has NO body — treat it as Retry-After: 60). Costs 0 and never counts toward the breaker. rate_limited is also the pre-auth ADDRESS guard, answered before the key is read: an address over 1 200 requests a minute that were not admitted (no key, a public route, a malformed, unknown or refused key — admitted requests never count), or one tarpitted at 60/min for 15 min after ≥ 20 unknown keys in a minute. No key is ever suspended by traffic that did not prove it
Shuningdek Cloudflare edge, per-IP 60/min on public routes. No JSON body (the edge eats it) — treat as Retry-After: 60
500Internal Server Error
internal_errordetails are in the redacted error copy, never here. Costs 0
503Service Unavailable
attention_busyan acknowledgement that resolves an item could not take the attention writer lock within 2 s — nothing was written; retry after
Retry-After: 2
Shuningdek Costs 0
0508
Hodisalar va webhooklar
41 hodisa turiOʻzgarishlar bitta oqimda. 1C kabi faqat oʻzi soʻrov yubora oladigan tizimlar uchun soʻrov-oqim asosiy kanal.
Soʻrov bilan olish
get/eventscurl -sS "https://api.dona.im/seller-api/v1/events?cursor=$LAST_EVENT_ID&limit=200" \
-H "Authorization: Bearer $DONA_KEY"Webhooklar — Standard Webhooks imzosi
Yetkazish qoidalari
One event per POST (≤ 20 KB), at-least-once, unordered. Reply 2xx within 10 s (ack first, process after); 3xx is a failure; 410 Gone disables the endpoint. Retry ladder: immediate · 5 s · 5 m · 30 m · 2 h · 5 h · 10 h · 14 h · 20 h · 24 h (≈ 75 h, ±10 % jitter).
Sarlavhalar
webhook-id- = the event id. Your idempotency key — dedupe for 24 h.
webhook-timestamp- Unix seconds. Reject if |now − ts| > 300 s. A redelivery carries a FRESH timestamp.
webhook-signature- Standard Webhooks: space-delimited
v1,<base64 HMAC-SHA256(base64decode(secret after whsec_), id + "." + ts + "." + rawBody)>; two entries during a 24 h rotation. Dona-Request-Id- Correlates with the delivery log.
Hodisa turlari
order.createdorder.paidorder.acceptedorder.declinedorder.readyorder.shippedorder.deliveredorder.cancelledorder.line_cancelledorder.accept_due_soonorder.ship_overduereturn.requestedreturn.status_changedproduct.publishedproduct.heldproduct.rejectedproduct.demotedproduct.violationproduct.deletedstock.lowstock.outwrite.heldwrite.approvedwrite.rejectedwrite.expiredaccount.status_changedaccount.documents_decidedaccount.kyc_reopenedaccount.suppressedaccount.health_changedaccount.agreement_owedlive.access_changedlive.strikeattention.openedattention.resolvedkey.expiringkey.suspendedkey.unsuspendedwebhook.failingwebhook.disabledping
Quyidagi imzo haqiqiy: u sayt yigʻilayotganda koʻrsatilgan demo-sir va tana bilan hisoblangan, kod uni aynan shunday tasdiqlaydi.
POST https://example.uz/dona-webhook
webhook-id: 01997b2e-7f00-7123-8456-789abcdef012
webhook-timestamp: 1790223151
webhook-signature: v1,CFjQ7u8l+tPV5Wzhawj/Hx9iWYx9sM6mcFJu4wsQxpQ=
# demo secret — NOT a real one
# whsec_ZG9uYS1kZW1vLXNlY3JldC1ub3QtYS1yZWFsLW9uZSE=
{"id":"01997b2e-7f00-7123-8456-789abcdef012","type":"order.created","occurred_at":"2026-09-24T09:12:31+05:00","seller_id":"0198f3a2-6c1d-7b40-8e55-2a9c3d4e5f60","api_version":"v1","data":{"order_id":"01997b2e-41c0-7e6f-8a9b-0c1d2e3f4a5b","status":"paid","payment_status":"paid","payment_method":"card","scheme":"own_fleet","total_uzs":259000,"accept_deadline":"2026-09-25T09:12:00+05:00","ship_by_deadline":null,"updated_at":"2026-09-24T09:12:31+05:00"},"links":{"self":"/seller-api/v1/orders/01997b2e-41c0-7e6f-8a9b-0c1d2e3f4a5b"}}import { createHmac, timingSafeEqual } from 'node:crypto'
// secret = "whsec_…" from POST /webhooks; body = the RAW request body (a string, not parsed JSON)
export function verify(secret, headers, body) {
const id = headers['webhook-id'], ts = headers['webhook-timestamp']
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false
const key = Buffer.from(secret.slice('whsec_'.length), 'base64')
const want = createHmac('sha256', key).update(`${id}.${ts}.${body}`).digest()
return headers['webhook-signature'].split(' ').some((entry) => {
const [v, sig] = entry.split(',')
const got = Buffer.from(sig ?? '', 'base64')
return v === 'v1' && got.length === want.length && timingSafeEqual(got, want)
})
}import base64, hashlib, hmac, time
def verify(secret: str, headers: dict, body: bytes) -> bool:
wid, ts = headers["webhook-id"], headers["webhook-timestamp"]
if abs(time.time() - int(ts)) > 300:
return False
key = base64.b64decode(secret.removeprefix("whsec_"))
want = hmac.new(key, f"{wid}.{ts}.".encode() + body, hashlib.sha256).digest()
for entry in headers["webhook-signature"].split(" "):
v, _, sig = entry.partition(",")
if v == "v1" and hmac.compare_digest(base64.b64decode(sig), want):
return True
return False0608
MCP — AI-agentlar
Claude Code, Cursor, Codex va boshqa AI-agentlar doʻkoningiz bilan MCP orqali ishlay oladi. Har bir chaqiruv jurnalga yoziladi.
Agent kaliti bilan agent doʻkonni oʻqiydi: mahsulotlar, buyurtmalar, hodisalar, e’tibor talab qiladigan holatlar, hisob holati va shu hujjatlar. Yozish vositalari — qoldiq, narx, buyurtmani joʻnatish va bekor qilish — faqat kengaytirilgan darajadagi doʻkonda va yozuvlar yoqilgan paytda chiqadi. Birinchi chaqiruvda hech narsa yozilmaydi: oʻzgarish avval tasdiqlanadi — agentning oʻz tasdiqlash oynasida yoki doʻkon egasi tomonidan Sozlamalar › API › Kutilayotgan yozuvlar boʻlimida.
- Endpoint
https://api.dona.im/seller-api/mcp- Himoyalangan resurs metamaʼlumoti (RFC 9728)
/.well-known/oauth-protected-resource/seller-api/mcp
Agent kaliti (dona_ak_live_…, ruxsat mcp) Sozlamalar › API boʻlimida yaratiladi.
claude mcp add --transport http dona https://api.dona.im/seller-api/mcp --header "Authorization: Bearer ${DONA_AGENT_KEY}"OAuth 2.1 — claude.ai va ChatGPT ulagichlari
Kalitni qoʻlda kiritib boʻlmaydigan ulagichlar OAuth 2.1 orqali kiradi: ulanishni doʻkon egasi sotuvchi kabinetida tasdiqlaydi (Sozlamalar › API › Ulangan ilovalar) va istalgan vaqtda uzib qoʻyishi mumkin. OAuth orqali agent faqat oʻqiy oladi.
- Avtorizatsiya serveri
https://auth.dona.im
0708
SDK
TypeScript, Python, Go, PHP va C# uchun SDKlar shu shartnomadan avtomatik yaratiladi.
- TypeScript
- Python
- Go
- PHP
- C#
- Dastlabki versiya 0.1.0
SDKlar ochiq GitHub repozitoriysida. Paketlar reyestrlarga (npm, PyPI, NuGet, Packagist) hali chiqarilmagan — hozircha toʻgʻridan-toʻgʻri repozitoriydan oʻrnating.
TypeScript
Talab: Node ≥ 20Repozitoriyni klonlash kerak
Oʻrnatish git clone https://github.com/ozbuz/dona-api.git && cd dona-api/sdks/typescript && npm installOʻrnatish npm install ../dona-api/sdks/typescriptPython
Talab: ≥ 3.11Oʻrnatish pip install "dona-api @ git+https://github.com/ozbuz/dona-api.git@main#subdirectory=sdks/python"Go
Talab: ≥ 1.26Oʻrnatish go get github.com/ozbuz/dona-api/sdks/go@mainPHP
Talab: ≥ 8.1, Guzzle 7Repozitoriyni klonlash kerak
Oʻrnatish git clone https://github.com/ozbuz/dona-api.git && cd your-project && composer config repositories.dona-api path ../dona-api/sdks/php && composer require ozbuz/dona-api:*@devC#
Talab: .NET 10Repozitoriyni klonlash kerak
Oʻrnatish git clone https://github.com/ozbuz/dona-api.git && dotnet add reference path/to/dona-api/sdks/csharp/src/Dona.Api/Dona.Api.csproj
0808
Oʻzgarishlar va holat
Har bir oʻzgarish sanasi, turi va taʼsir qiladigan ruxsatlar bilan eʼlon qilinadi.
Kalit kerakmi?
Kalitni doʻkon egasi sotuvchi kabinetida yaratadi: Sozlamalar › API. Kalit faqat bir marta koʻrsatiladi.
Xaridor yoki sotuvchi sifatida savolingiz bormi? Yordam markaziga oʻting.