{
  "contractVersion": "1.0.0",
  "documents": [
    {
      "id": "getting-started",
      "title": "Boshlash · Quickstart",
      "file": "getting-started.md",
      "group": "Boshlash",
      "summary": "Biznes profili, birinchi API so‘rovi va nashrgacha bo‘lgan yo‘l.",
      "keywords": "start onboarding register integration ulash",
      "url": "https://partners.zayuno.uz/docs/getting-started/",
      "markdownUrl": "https://partners.zayuno.uz/docs/getting-started.md",
      "markdown": "# Zayuno’ga biznesingizni ulash\n\nMijoz istagini yozadi. Zayuno provider API’dan mos mahsulotni topadi, yakuniy narxni tekshiradi va **mijoz tasdiqlagandan keyin** buyurtma yuboradi. Siz katalog, narx, mavjudlik va buyurtma bajarilishini boshqarasiz.\n\nBu qo‘llanma biznes egasi, dasturchi va uning AI agenti uchun. Hozirgi mahsulot fokusi — ovqat buyurtmalari. Boshqa kategoriyalarga mos contract mavjudligi ularda providerlar yoki mijoz talabi allaqachon borligini anglatmaydi.\n\n## 1. Qaysi yo‘ldan boshlaysiz?\n\n| Sizning vazifangiz | Keyingi qadam |\n| --- | --- |\n| Biznes egasiman | [Hisob va biznes profilini yaratish](https://partners.zayuno.uz/?tab=onboarding) |\n| Backend dasturchiman | [API Base URL & Endpoints](https://partners.zayuno.uz/docs/base-url.md), keyin [Provider reference](https://partners.zayuno.uz/docs/contract-reference.md) |\n| Codex, Claude yoki boshqa agent bilan quraman | [AI agent qo‘llanmasi](https://partners.zayuno.uz/docs/ai-agents.md), portalda **AI Kit** |\n| API tayyor, xato chiqyapti | [Troubleshooting](https://partners.zayuno.uz/docs/troubleshooting-faq.md), keyin [API tekshiruvi](https://partners.zayuno.uz/?tab=certification) |\n\n## 2. Uchta bosqich\n\n1. **Profil.** Hisob oching, emailni tasdiqlang, biznes turi, xizmat ko‘rsatish usuli va support kontaktlarini kiriting.\n2. **Integratsiya.** Backendda kerakli endpointlarni quring. HTTPS base URL, capability va credentiallarni ulang. O‘z test muhitingizda certification’ni bajaring.\n3. **Review va nashr.** Dashboarddagi talablarni bajaring va ko‘rib chiqishga yuboring. Certification muvaffaqiyati avtomatik ravishda ommaga chiqarish degani emas.\n\n[Mening biznesim](https://partners.zayuno.uz/?tab=apps) sahifasida saqlangan konfiguratsiya, certification, review va provider status alohida ko‘rinadi.\n\n## 3. Qaysi server qaysi tomonda?\n\n| Manzil | Kim boshqaradi | Nima uchun |\n| --- | --- | --- |\n| https://partners.zayuno.uz | Zayuno | Provider portal va docs |\n| https://api.zayuno.uz/api/v1 | Zayuno | Core va account API |\n| https://YOUR_HOST/zayuno | Siz | Portalga beriladigan **Provider API Base URL** |\n| https://api.zayuno.uz/api/v1/webhooks/{providerSlug} | Zayuno | Siz yuboradigan imzolangan status eventlar |\n\nMasalan base URL oxiriga \"/health\" qo‘shib Zayuno sizning serveringizni chaqiradi. Portal manzilini yoki Zayuno Core URL’ini o‘z base URL’ingiz sifatida kiritmang.\n\n## 4. Capability profilini tanlang\n\n- **DISCOVERY_READONLY:** topish va ko‘rsatish. METADATA, HEALTH, CATALOG talab qilinadi.\n- **TRANSACTIONAL:** qo‘shimcha QUOTE, ACTION_CREATE, ACTION_STATUS, WEBHOOK talab qilinadi.\n- **Joylashuvlar:** DELIVERY, PICKUP, ONSITE yoki HYBRID fulfillment’da faol locationlar kerak. REMOTE uchun bu universal talab emas.\n\nBular capability sonlari, endpoint sonlari emas. Masalan CATALOG katalog ro‘yxati va bitta offeringni olishni qamrab oladi. [To‘liq matritsa](https://partners.zayuno.uz/docs/capabilities.md).\n\n## 5. Birinchi tekshiriladigan so‘rov\n\nAvval developer [API key](https://partners.zayuno.uz/docs/auth.md) yaratadi va backendda sozlaydi. Keyin o‘z serveringizga GET /health yuboring:\n\n~~~bash\ncurl \"https://YOUR_HOST/zayuno/health\" \\\n  -H \"x-provider-api-key: $PROVIDER_API_KEY\"\n~~~\n\nKutilyotgan JSON va qolgan route’lar [contractdan yaratilgan reference](https://partners.zayuno.uz/docs/contract-reference.md#contract-health) ichida. Namuna qiymatlarni ishlab turgan serverdan olingan dalil deb qabul qilmang.\n\n## 6. Sandbox va real tekshiruv farqi\n\n**Sandbox** namunaviy provider orqali oqimni tushuntiradi. U sizning API’ingiz ishlayotganini isbotlamaydi.\n\n**API tekshiruvi / Certification** ulangan provider adapterini tekshiradi. Transactional tekshiruv test buyurtma yaratishi mumkin; o‘zingiz boshqaradigan test katalog va test fulfillment muhitidan foydalaning.\n\n**Nashr / ACTIVE** — review va faollashtirishdan keyingi alohida holat.\n\n## 7. Dasturchiga topshirish\n\nAI Kit’da framework va vazifani tanlab briefni nusxalang yoki Markdown yuklab oling. Agent resurslari:\n\n- [llms.txt](https://partners.zayuno.uz/llms.txt) — nimadan boshlash va kerakli hujjatni topish.\n- [llms-full.txt](https://partners.zayuno.uz/llms-full.txt) — barcha provider qo‘llanmalari.\n- [OpenAPI](https://partners.zayuno.uz/openapi.json) — machine-readable schema va misollar.\n- [Postman](https://partners.zayuno.uz/postman.json) — so‘rovlar to‘plami.\n\nAPI kalit va webhook secretni briefga yozmang. Agentga muhit o‘zgaruvchisi nomi yetadi.\n# Provider arizasini bosqichma-bosqich tayyorlash\n\nHisob va email tasdiqlangach, biznes nomi va kamida bitta to‘g‘ri telefon, Telegram username yoki email kiriting. Keyingi bosqichda public HTTPS API Base URL va provider serveringiz tekshiradigan credential kerak. Bo‘sh Base URL endi avtomatik sandbox yaratmaydi. API tayyor bo‘lmasa, AI Kit va OpenAPI orqali backendni tayyorlang; demo uchun alohida Sandbox bo‘limidan foydalaning.\n\nLogo uchun HTTPS rasm manzilini kiriting yoki PNG/JPG/WebP fayl yuklang (5 MB gacha). Portal rasmni 384px gacha kichraytiradi; 96 KB chegarali raster data URL mavjud `logoUrl` maydonida saqlanadi. Logo ixtiyoriy.\n\nAPI sozlamalarini saqlash → sertifikatlash → review tartibida davom eting. Ma’lumot yoki credential o‘zgarsa, qayta saqlash va sertifikatlash kerak; qadam havolasi yoki saqlangan brauzer drafti bu tekshiruvni chetlab o‘tmaydi.\n"
    },
    {
      "id": "base-url",
      "title": "API Base URL & Endpoints",
      "file": "base-url.md",
      "group": "Boshlash",
      "summary": "Qaysi serverni qurish kerak? Express va FastAPI misollari.",
      "keywords": "https endpoint node python express fastapi server url",
      "url": "https://partners.zayuno.uz/docs/base-url/",
      "markdownUrl": "https://partners.zayuno.uz/docs/base-url.md",
      "markdown": "# API Base URL & Endpoints\n\n**Provider API Base URL — siz qurgan backend manzili.** Masalan https://YOUR_HOST/zayuno. Zayuno shu URL oxiriga /provider-info, /health, /catalog va profilingizdagi qolgan yo‘llarni qo‘shadi.\n\n## Uchta manzilni ajrating\n\n| Surface | Base URL | Credential |\n| --- | --- | --- |\n| Provider API: siz qurasiz | https://YOUR_HOST/zayuno | Provider API key / tanlangan auth |\n| Zayuno Core: siz qurmayapsiz | https://api.zayuno.uz/api/v1 | Tegishli account yoki integration token |\n| Provider webhook: siz yuborasiz | https://api.zayuno.uz/api/v1/webhooks/{providerSlug} | ZAYUNO_WEBHOOK_SECRET bilan HMAC |\n\nPortal frontend URL’ini API Base URL sifatida kiritmang. Oxiriga /health ham qo‘shmang: /health route’ini Zayuno o‘zi qo‘shadi.\n\n## 1. Birinchi health endpoint\n\nQuyidagi minimal misollar server va auth ulanishini boshlash uchun. Ular to‘liq provider implementation emas. Metadata, catalog, offering va profilingiz talab qilgan qolgan route’larni [generated reference](https://partners.zayuno.uz/docs/contract-reference.md) bo‘yicha yozing.\n\n### Express & TypeScript\n\n~~~typescript\nimport express from 'express';\nconst app = express();\nconst key = process.env.PROVIDER_API_KEY;\nif (!key) throw new Error('Set PROVIDER_API_KEY on the server');\n\napp.use('/zayuno', (req, res, next) => {\n  if (req.header('x-provider-api-key') !== key) {\n    res.status(401).json({ error: 'UNAUTHORIZED' });\n    return;\n  }\n  next();\n});\napp.get('/zayuno/health', (_req, res) => {\n  res.json({ status: 'HEALTHY', latencyMs: 0, timestamp: new Date().toISOString() });\n});\napp.listen(4001);\n~~~\n\n### Python (FastAPI)\n\n~~~python\nimport os\nfrom datetime import datetime, timezone\nfrom fastapi import FastAPI, Header, HTTPException\n\napp = FastAPI()\nkey = os.environ[\"PROVIDER_API_KEY\"]\nif not key:\n    raise RuntimeError(\"Set PROVIDER_API_KEY on the server\")\n\n@app.get(\"/zayuno/health\")\ndef health(x_provider_api_key: str = Header(default=\"\")):\n    if x_provider_api_key != key:\n        raise HTTPException(status_code=401, detail=\"UNAUTHORIZED\")\n    return {\n        \"status\": \"HEALTHY\",\n        \"latencyMs\": 0,\n        \"timestamp\": datetime.now(timezone.utc).isoformat()\n    }\n~~~\n\nlatencyMs: 0 yuqorida faqat minimal liveness namunasidir. Ishlab chiqarish muhitida haqiqiy dependency holatini o‘lchang; nosog‘lom tizimni HEALTHY deb qaytarmang.\n\n## 2. Serverga bevosita so‘rov\n\n~~~bash\ncurl \"http://localhost:4001/zayuno/health\" \\\n  -H \"x-provider-api-key: $PROVIDER_API_KEY\"\n~~~\n\nLocal test sizning kompyuteringizda ishlaydi. Hosted Zayuno localhost yoki private IP’ga kira olmaydi. Provider portal uchun public HTTPS test host/tunnel kerak; key himoyasini o‘chirmang.\n\n## 3. Contractni joriy qilish\n\n1. [Capability profilingizni](https://partners.zayuno.uz/docs/capabilities.md) tanlang.\n2. [OpenAPI JSON](https://partners.zayuno.uz/openapi.json) orqali request/response schema’larini oling.\n3. Provider route’larni canonical shaklda yozing: masalan quote uchun **POST /quote**, Core’dagi POST /api/v1/quotes emas.\n4. Backendning haqiqiy ID, variant, narx va mavjudligini normalized response’ga map qiling.\n5. Idempotency’ni barqaror storage’da saqlang. Buyurtmalarni in-memory demo bilan productionga chiqarmang.\n\n## 4. Portalda ulash\n\n[Mening biznesim](https://partners.zayuno.uz/?tab=apps) → Provider API Base URL → Authentication → Capabilitylar → saqlash. Keyin [API tekshiruvi](https://partners.zayuno.uz/?tab=certification).\n\nFrameworkdan qat’i nazar response bir xil contractga mos bo‘lishi kerak. [AI Kit](https://partners.zayuno.uz/docs/ai-agents.md) shu contract asosida vazifani agentingizga tayyorlab beradi.\n\n## 5. Networking va xatolar\n\n401 — key/auth method; 404 — base path; HTML response — frontend URL; timeout — public reachability yoki backend. [Batafsil troubleshooting](https://partners.zayuno.uz/docs/troubleshooting-faq.md).\n"
    },
    {
      "id": "ai-agents",
      "title": "AI agent bilan integratsiya",
      "file": "ai-agents.md",
      "group": "Boshlash",
      "summary": "Codex, Claude va boshqa agentlar uchun ish tartibi va resurslar.",
      "keywords": "llms.txt claude codex cursor agent ai kit prompt",
      "url": "https://partners.zayuno.uz/docs/ai-agents/",
      "markdownUrl": "https://partners.zayuno.uz/docs/ai-agents.md",
      "markdown": "# AI agent integration guide\n\nUse this guide when implementing a Zayuno provider adapter with Codex, Claude Code, Cursor or another coding agent. The target is the provider's backend, not the Zayuno consumer app.\n\n## Read in this order\n\n1. [Quickstart](https://partners.zayuno.uz/docs/getting-started.md) and [base URL](https://partners.zayuno.uz/docs/base-url.md): identify the system you are building.\n2. [Capabilities](https://partners.zayuno.uz/docs/capabilities.md): select DISCOVERY_READONLY or TRANSACTIONAL and fulfillment mode.\n3. [OpenAPI](https://partners.zayuno.uz/openapi.json) and [generated endpoint reference](https://partners.zayuno.uz/docs/contract-reference.md): exact request, response, direction and required fields.\n4. [Authentication](https://partners.zayuno.uz/docs/auth.md), [quotes](https://partners.zayuno.uz/docs/quotes.md), [actions](https://partners.zayuno.uz/docs/actions.md), [webhooks](https://partners.zayuno.uz/docs/webhooks.md).\n5. [Certification](https://partners.zayuno.uz/docs/certification.md) and [troubleshooting](https://partners.zayuno.uz/docs/troubleshooting-faq.md).\n\n## Machine-readable entry points\n\n| URL | Purpose |\n| --- | --- |\n| https://partners.zayuno.uz/llms.txt | Compact discovery index |\n| https://partners.zayuno.uz/llms-full.txt | All provider docs in one text document |\n| https://partners.zayuno.uz/docs/{id}.md | One guide as raw Markdown |\n| https://partners.zayuno.uz/docs/search-index.json | Titles, keywords and complete guide text |\n| https://partners.zayuno.uz/openapi.json | Provider schemas and example payloads |\n| https://partners.zayuno.uz/postman.json | Importable collection |\n| https://partners.zayuno.uz/docs/ | Crawlable HTML, no JavaScript required |\n\nThese resources are generated in the same build as the portal. AI Kit can also export a framework-specific task and a provider-specific contract summary.\n\n## Contract precedence\n\nSchema and canonical endpoint definitions in packages/contracts/src are the implementation source of truth. The generated OpenAPI and reference are derived from them. Explanatory guides describe workflow; they do not invent fields or loosen validation.\n\nIf an example, legacy provider response or AI-generated code conflicts with a schema, identify the mismatch and fix the adapter. Do not silently change the core contract. Optional values should be omitted when unavailable unless the schema explicitly permits null.\n\n## Implementation checklist\n\n1. Read the existing provider backend and its order model before editing.\n2. Record the task, files to change, tests and next steps in a local checklist.\n3. Map real catalog IDs, prices, variants, modifiers and availability.\n4. Implement only declared capabilities plus mandatory fulfillment requirements.\n5. Use server environment variables for keys. The provider creates PROVIDER_API_KEY; Zayuno supplies ZAYUNO_WEBHOOK_SECRET. Never paste their values in a prompt.\n6. Keep provider endpoints and Zayuno Core endpoints distinct. Status webhooks go from provider to Zayuno.\n7. Recompute quote totals server-side. Reject expired quotes and preserve explicit user confirmation before action creation.\n8. Persist idempotency across restarts. Retry with the same key returns the existing action.\n9. For HMAC, sign the exact raw body. The current protocol does not prepend a timestamp to the signature input.\n10. Return a provider-owned checkout URL when required; do not invent payment success.\n11. Run local schema and negative tests, then provider certification in an isolated test environment.\n12. Report completed vs unverified work, commands and remaining steps. Do not claim production readiness from the demo sandbox.\n\n## Minimum verification matrix\n\n| Scenario | Evidence |\n| --- | --- |\n| Wrong API key | Rejected request |\n| Malformed catalog | Schema identifies invalid field |\n| Quantity or option changes | Server-calculated quote matches selection |\n| Expired quote | No action created from stale terms |\n| Duplicate action create | Same action ID, no double fulfillment |\n| Invalid webhook signature | Rejected event |\n| Provider timeout | Explicit error, no fake success |\n| Payment pending | nextAction and status reflect provider truth |\n\n## Handoff template\n\n~~~text\nGoal:\nProvider type / fulfillment mode:\nCapability profile:\nBackend framework:\nContract version:\nCompleted:\nChanged files:\nTests and exact results:\nNot verified:\nNext action:\n~~~\n\n## Ready-to-use Agent Prompts\n\n### Prompt for Claude Code / Cursor / Codex\n\n~~~markdown\nYou are building the Zayuno Provider Adapter for our backend.\n\nCanonical documentation:\n- Full contract: https://partners.zayuno.uz/llms-full.txt\n- OpenAPI Schema: https://partners.zayuno.uz/openapi.json\n- Base URL & Quickstart: https://partners.zayuno.uz/docs/base-url.md\n- Strict Certification v2: https://partners.zayuno.uz/docs/certification.md\n\nYour Task:\nExpose provider endpoints under our backend prefix (e.g. /zayuno):\n1. GET /health: Health check, verifies x-provider-api-key header.\n2. GET /provider-info: Returns metadata and manifest:\n   - Must include `manifest.certification.safeTestEnvironment: true`.\n   - Declare customerRequirements (e.g. `{ phone: \"REQUIRED\" }` or `{ email: \"REQUIRED\" }` or `{}`).\n   - Declare inputMode (`OFFERING` for catalog items, or `PARAMETERS` for parameter-only services).\n   - Provide `certificationInput` with valid test data.\n3. GET /catalog: Returns active offerings with categories, variants, and modifiers.\n4. POST /quote: Calculates authoritative total, fees, and discounts from our database (minimum 5s TTL).\n5. POST /actions:\n   - Validates required fields first; returns HTTP 400/422 VALIDATION_ERROR on missing fields (never QUOTE_EXPIRED).\n   - Requires `userConfirmed: true` (rejects unconfirmed with ACTION_NOT_CONFIRMED).\n   - Deduplicates with `idempotencyKey`; returns identical action on retry, or HTTP 409 IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD if payload changed.\n6. GET /actions/:id: Returns canonical order status.\n7. Webhook Dispatch: For every created test order, automatically dispatches signed POST to `https://api.zayuno.uz/api/v1/webhooks/{providerSlug}` with header `x-zayuno-signature` (HMAC-SHA256 over raw JSON) and event `action.status_updated`.\n\nStrict Rules:\n- Never guess prices or stock; calculate strictly from database records.\n- Protect secrets: read PROVIDER_API_KEY and ZAYUNO_WEBHOOK_SECRET from environment variables.\n- Verify each endpoint with cURL before declaring the task done.\n~~~\n\nUse **AI Kit → framework → goal** for a concrete task with canonical payloads and, when available, redacted certification errors. This page remains accessible without signing in.\n"
    },
    {
      "id": "spec-v1",
      "title": "Arxitektura va chegaralar",
      "file": "provider-integration-v1.md",
      "group": "Contract v1",
      "summary": "Provider va Zayuno vazifalari, lifecycle va to‘lov chegarasi.",
      "keywords": "architecture lifecycle states payment boundary",
      "url": "https://partners.zayuno.uz/docs/spec-v1/",
      "markdownUrl": "https://partners.zayuno.uz/docs/spec-v1.md",
      "markdown": "# Provider Integration v1\n\nZayuno provider API’dagi katalog, narx va actionlarni normalized contract orqali ishlatadi. Hozirgi mahsulot fokusi food ordering; umumiy contract boshqa kategoriyalar uchun ham kengaytirish imkonini beradi.\n\n## Architectural boundaries\n\n| Mas’ul tomon | Source of truth |\n| --- | --- |\n| Provider | Mahsulot ID, katalog, narx, mavjudlik, quote, fulfillment va provider checkout |\n| Zayuno | Suhbat, discovery, tanlov, confirmation gate, action orchestration va provider status monitoringi |\n| Mijoz | Yakuniy buyurtma tasdig‘i |\n\nLLM narx yoki mavjudlikni uydirmasligi kerak. Buyurtmadan oldin amaldagi quote va mijoz tasdig‘i talab qilinadi. Retry yangi buyurtma yaratmasligi uchun idempotency key saqlanadi.\n\n## Transaction lifecycle\n\n~~~text\nIntent → Discovery → Selection → Quote → Confirmation → Action → Fulfillment\n~~~\n\n- Intent — foydalanuvchi xohlagan natija.\n- Discovery/selection — haqiqiy catalogdan ID va variant tanlash.\n- Quote — server hisoblagan narx, fees, discounts, expiry.\n- Confirmation — mijoz shu shartlarni tasdiqlaydi.\n- Action — providerga idempotent yaratish so‘rovi.\n- Fulfillment — provider statusi, webhook va kerak bo‘lsa checkout handoff.\n\n## Integration surfaces\n\nProvider o‘z HTTPS endpointlarini beradi. Har bir canonical request, response va yo‘nalish [generated Provider API reference](https://partners.zayuno.uz/docs/contract-reference.md) va [OpenAPI](https://partners.zayuno.uz/openapi.json) orqali olinadi.\n\nZayuno Core management API boshqa surface: [Core API reference](https://partners.zayuno.uz/docs/api-reference.md). Provider Base URL’ga Core route’larni ko‘chirib qo‘ymang.\n\n## Payment boundary\n\n**ZAYUNO DOES NOT PROCESS PAYMENTS.** Joriy contractda provider to‘lov sahifasini nextAction orqali qaytaradi. Zayuno mijozni o‘sha sahifaga yo‘naltiradi; karta ma’lumotlarini qabul qiladigan provider checkout’ining o‘rnini bosmaydi.\n\nDashboarddagi paymentStatus provider xabariga asoslanadi (PROVIDER_REPORTED). Uni mustaqil bank settlement tekshiruvi deb ko‘rsatmang. [Payment handoff](https://partners.zayuno.uz/docs/payment-handoff.md).\n\n## Provider lifecycle\n\nDRAFT — sozlash; SANDBOX — test; ACTIVE — nashr qilingan; SUSPENDED — to‘xtatilgan; DISABLED — o‘chirilgan provider. Status o‘tishlarida API mavjud guardlarni qo‘llaydi.\n\nCertification (metadata.isCertified) va review (metadata.reviewStatus) provider statusdan alohida. CERTIFIED va REVIEW provider status enum qiymatlari emas. [Nashr jarayoni](https://partners.zayuno.uz/docs/certification.md).\n\n## Version va moslik\n\nContract v1.0.0 manbasi packages/contracts/src/provider-protocol.ts va Zod schema’lar. Yangi integratsiyalar canonical field nomlarini ishlatadi; legacy aliaslar faqat adapter migration boundary’da.\n\nHujjat va kod farqlansa schema, adapter va test bilan aniqlashtiring. [AI agent workflow](https://partners.zayuno.uz/docs/ai-agents.md) shunday tekshiruvga yo‘naltiradi.\n"
    },
    {
      "id": "capabilities",
      "title": "Capability profillari",
      "file": "capabilities.md",
      "group": "Contract v1",
      "summary": "Read-only, transactional va joylashuv talablari.",
      "keywords": "readonly transactional locations fulfillment mandatory",
      "url": "https://partners.zayuno.uz/docs/capabilities/",
      "markdownUrl": "https://partners.zayuno.uz/docs/capabilities.md",
      "markdown": "# Capability profillari\n\nCapability provider bajara oladigan operatsiyani bildiradi. U mahsulot kategoriyasi yoki provider type bilan bir xil narsa emas. Contract versiyasi: 1.0.0.\n\n## Profil bo‘yicha talablar\n\n| Capability | DISCOVERY_READONLY | TRANSACTIONAL | Provider route yoki yo‘nalish |\n| --- | --- | --- | --- |\n| METADATA | Talab qilinadi | Talab qilinadi | GET /provider-info |\n| HEALTH | Talab qilinadi | Talab qilinadi | GET /health |\n| CATALOG | Talab qilinadi | Talab qilinadi | GET /catalog; GET /offerings/:id |\n| QUOTE | Yo‘q | Talab qilinadi | POST /quote |\n| ACTION_CREATE | Yo‘q | Talab qilinadi | POST /actions |\n| ACTION_STATUS | Yo‘q | Talab qilinadi | GET /actions/:id |\n| WEBHOOK | Yo‘q | Talab qilinadi | Provider → Zayuno: POST /api/v1/webhooks/:providerSlug |\n| LOCATIONS | Fulfillment’ga qarab | Fulfillment’ga qarab | GET /locations |\n| SEARCH | Ixtiyoriy | Ixtiyoriy | GET /search |\n| ACTION_CANCEL | Yo‘q | Ixtiyoriy | POST /actions/:id/cancel |\n| PAYMENT_OPTIONS | Yo‘q | Ixtiyoriy | GET /actions/:id/payment-options |\n\nFaqat mavjud imkoniyatlarni e’lon qiling. Capability e’lon qilinsa uning response schema’si ham tekshiriladi. [Generated reference](https://partners.zayuno.uz/docs/contract-reference.md) har bir endpointning aniq request va response formatini beradi.\n\n## Faol location qachon kerak?\n\nDELIVERY, PICKUP, ONSITE va HYBRID fulfillment faol location talab qiladi. REMOTE uchun avtomatik location talabi yo‘q.\n\nFulfillment belgilanmagan bo‘lsa type bo‘yicha default ishlatiladi: DELIVERY → DELIVERY; RETAIL va BOOKINGS → ONSITE; boshqa type’lar → REMOTE. Aniq fulfillment berish afzal.\n\nPhysical biznes LOCATIONS’ni e’lon qilmasdan bu talabni chetlab o‘ta olmaydi. Metadata’dagi branch soni emas, GET /locations response’idagi faol locationlar tekshiriladi.\n\n## Contract bilan moslashtirish\n\nBackend implementation manbalari: packages/contracts/src/provider.ts va provider-protocol.ts. Runtime validation shu contractlarga tayanadi.\n\n1. Kerakli profil va fulfillment’ni tanlang.\n2. Portal va GET /provider-info’dagi capabilitylar bir-biriga mos bo‘lsin.\n3. [OpenAPI](https://partners.zayuno.uz/openapi.json) orqali endpoint schema’larini tekshiring.\n4. Test muhitida [certification](https://partners.zayuno.uz/docs/certification.md) bajaring.\n5. Konfiguratsiya o‘zgargandan keyin qayta certification qiling.\n"
    },
    {
      "id": "auth",
      "title": "Authentication & HMAC",
      "file": "authentication.md",
      "group": "Contract v1",
      "summary": "API key kimniki? Webhook secret va raw body imzosi.",
      "keywords": "401 unauthorized hmac rawbody secret key bearer signature authentication",
      "url": "https://partners.zayuno.uz/docs/auth/",
      "markdownUrl": "https://partners.zayuno.uz/docs/auth.md",
      "markdown": "# Authentication & HMAC\n\nProvider credentiallari portalga kirish credentiallaridan farq qiladi. Yo‘nalishni aniqlamasdan key almashtirmang.\n\n## Ikki xil credential\n\n| Qiymat | Kim yaratadi | Qayerda ishlatiladi |\n| --- | --- | --- |\n| PROVIDER_API_KEY | Dasturchi provider backend uchun maxfiy API key yaratadi | Zayuno → provider; odatda x-provider-api-key |\n| ZAYUNO_WEBHOOK_SECRET | Zayuno webhook HMAC secret yaratadi | Provider → Zayuno; event imzosini hisoblash |\n| Portal access token | Zayuno account auth | Portal → Core; Authorization: Bearer |\n\nSelf-service oqimida provider API key’ni backendda o‘rnating, keyin portalning API sozlamalariga kiriting. Zayuno yaratgan webhook secret handoff paytida ko‘rsatiladi. Boshqaruv orqali provision qilingan integratsiyalarda credential banneri ikkala qiymatni ham berishi mumkin; banner va o‘z backendingizdagi qiymatni moslang.\n\nTo‘liq secret dashboarddan qayta olinmaydi. Secret yo‘qolsa tegishli credentialni yangilang. Webhook secretni rotate qilish oldingi imzoni bekor qiladi; provider backenddagi qiymatni ham yangilash kerak.\n\n## Zayuno → provider authentication\n\nPortalda tanlangan authMethod har bir outbound requestga tatbiq qilinadi.\n\n| authMethod | Header | Qiymat |\n| --- | --- | --- |\n| API_KEY | x-provider-api-key | Provider backend kutadigan key |\n| BEARER_TOKEN | Authorization | Bearer + sozlangan token |\n| HMAC_SIGNATURE | x-zayuno-signature | Raw request body ustidagi HMAC-SHA256 hex |\n\n~~~http\nGET /zayuno/health HTTP/1.1\nHost: YOUR_HOST\nx-provider-api-key: <PROVIDER_API_KEY>\nAccept: application/json\n~~~\n\nHMAC_SIGNATURE uchun joriy remote adapter **faqat raw body**ni imzolaydi. Timestamp prefix qo‘shilmaydi. Body bo‘lmagan GET so‘rovda bo‘sh satr imzolanadi. Qabul qiluvchi backend aynan shu baytlarni tekshirishi kerak; JSON’ni parse qilib qayta stringify qilish imzoni o‘zgartirishi mumkin.\n\n## Provider → Zayuno webhook signing\n\nCanonical manzil:\n\n~~~text\nPOST https://api.zayuno.uz/api/v1/webhooks/{providerSlug}\nContent-Type: application/json\nx-zayuno-signature: <HMAC_SHA256_HEX>\n~~~\n\nBackendda hisoblang; browserda yoki mobile clientda emas:\n\n~~~typescript\nimport { createHmac } from 'node:crypto';\n\nconst secret = process.env.ZAYUNO_WEBHOOK_SECRET;\nif (!secret) throw new Error('ZAYUNO_WEBHOOK_SECRET is required');\n\nconst rawBody = JSON.stringify(event);\nconst signature = createHmac('sha256', secret).update(rawBody).digest('hex');\n\nconst response = await fetch(\n  'https://api.zayuno.uz/api/v1/webhooks/' + encodeURIComponent(providerSlug),\n  {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'x-zayuno-signature': signature\n    },\n    body: rawBody\n  }\n);\nif (!response.ok) throw new Error('Webhook delivery failed: ' + response.status);\n~~~\n\n[Canonical event JSON](https://partners.zayuno.uz/docs/contract-reference.md#contract-webhooks). x-provider-signature compatibility header ham qabul qilinadi; yangi integratsiyada x-zayuno-signature ishlating. x-signature canonical header emas.\n\n## 401 bo‘lsa nimani tekshirasiz?\n\n1. Request yo‘nalishini tekshiring: provider API key va webhook secret alohida.\n2. Auth method va header nomi portalga mos bo‘lsin.\n3. Secret boshida/oxirida ortiqcha whitespace bo‘lmasin.\n4. HMAC uchun yuborilgan raw body va imzolangan rawBody bir xil bo‘lsin.\n5. Webhook secret rotate qilingan bo‘lsa backendni ham yangilang.\n6. [So‘rovlar jurnali](https://partners.zayuno.uz/?tab=inspector) orqali trace va xato kodini toping.\n\nKalitlarni logga, source control’ga yoki AI briefga qo‘shmang. Xato haqida ma’lumot berishda header qiymatini niqoblang.\n"
    },
    {
      "id": "catalog",
      "title": "Katalog va mahsulotlar",
      "file": "catalog.md",
      "group": "Contract v1",
      "summary": "Offering, variant, option, narx va mavjudlik.",
      "keywords": "menu product offerings variants modifiers stock narx",
      "url": "https://partners.zayuno.uz/docs/catalog/",
      "markdownUrl": "https://partners.zayuno.uz/docs/catalog.md",
      "markdown": "# Catalog & Offerings\n\nThe catalog supplies real categories, products, variants, modifiers, prices and availability to Zayuno. Stable identifiers are essential: the order flow uses IDs, not display names.\n\n## Provider endpoints\n\n- GET /catalog — categories and offerings.\n- GET /offerings/:id — one offering by its stable ID.\n- GET /search — when SEARCH is declared.\n- GET /locations — when declared or required by physical fulfillment.\n\nUse [canonical catalog JSON](https://partners.zayuno.uz/docs/contract-reference.md#contract-catalog) and [offering JSON](https://partners.zayuno.uz/docs/contract-reference.md#contract-offering). The OpenAPI schema specifies required fields; a short UI card is not a complete API payload.\n\n## Map the real catalog\n\nMap providerId, offeringCode, title, description, categorySlug, categoryTitle, basePrice, currency, isAvailable and declared optional metadata according to the schema.\n\nDo not rename canonical fields to a merchant's internal field names. Keep that translation inside the provider adapter. Missing data should not become a fabricated default price or stock status.\n\n## Variants and modifiers\n\nVariants have their own IDs, labels, prices and availability. Option groups define selectable modifiers; minSelections and maxSelections constrain the choices. priceDelta is used in verified quote calculation, not merely in the product card.\n\n`selectedOptions[].quantity` is **per requested base item**. For example, two Large Cappuccinos with one vanilla syrup each use `item.quantity: 2` and `selectedOptions[].quantity: 1`; the syrup contribution is `priceDelta × 1 × 2`. Provider adapters must normalize upstream line-level modifier quantities to this canonical per-item meaning.\n\nKeep IDs stable across catalog refreshes. Changed or unavailable choices must be checked again by POST /quote.\n\n## Catalog versus quote\n\nCatalog prices help discovery. The quote is the authoritative calculation for the customer's exact selection, destination, fees and discounts. A catalog refresh does not replace quote validation.\n\nTest catalog, single-offering and search results against the same schema and ensure they refer to the same provider and product IDs. See [quotes](https://partners.zayuno.uz/docs/quotes.md).\n"
    },
    {
      "id": "quotes",
      "title": "Quote va hisob-kitob",
      "file": "quotes.md",
      "group": "Contract v1",
      "summary": "Narxni hisoblash, expiry, subtotal va fees.",
      "keywords": "price pricing math total quote expiry expired 409 subtotal",
      "url": "https://partners.zayuno.uz/docs/quotes/",
      "markdownUrl": "https://partners.zayuno.uz/docs/quotes.md",
      "markdown": "# Quotes & Pricing\n\nA quote is the provider's verified price for a specific selection. The AI must not invent prices, fees or availability. A quote ID is an identifier; the contract does not require it to be a cryptographic token.\n\n## Endpoint and source of truth\n\n**Implement POST /quote on your provider backend.** Zayuno Core's POST /api/v1/quotes is a different endpoint that orchestrates provider requests.\n\nUse the [generated request and response](https://partners.zayuno.uz/docs/contract-reference.md#contract-quote) and [OpenAPI](https://partners.zayuno.uz/openapi.json). Examples are derived from the contract rather than maintained separately in this guide.\n\n## Calculation\n\n1. Resolve real offering IDs, variant IDs and selectedOptions.\n2. Check availability, quantity and option selection limits.\n3. Compute line totals, delivery/service fees and validated discounts.\n4. Return canonical id, lines, subtotal, totalFees, totalDiscount, total, currency and expiresAt.\n5. Bind the quote to the selection and fulfillment terms so it cannot authorize a different order.\n\n~~~text\nsubtotal = sum(lines[].lineTotal)\ntotal = subtotal + totalFees - totalDiscount\n~~~\n\nUse the contract's line price semantics. In particular, do not count an option price once in the line and again in fees.\n\nFor every selected modifier, `selectedOptions[].quantity` means units **per base item**, so its line contribution is `priceDelta × selectedOptions[].quantity × line.quantity`. Include this amount exactly once in `optionsTotal` and `lineTotal`.\n\n## Expiry and confirmation\n\nProvider controls expiresAt. Do not copy an old example date or assume all providers use the same validity duration.\n\nIf a quote expires, or items, quantities, options or destination change, obtain a fresh quote. Show its total and terms to the customer and obtain explicit confirmation before an action.\n\n## Promo codes and unavailable items\n\nValidate a promo code against provider data. Return its actual effect in discounts and total; do not promise a discount from an AI guess.\n\nIf a requested item or variant is unavailable, return a clear error or supported alternative. Never silently replace the item in a confirmed quote.\n\n## Verification\n\nTest quantity changes, modifiers, zero/invalid quantities, unavailable stock, invalid discount, expired quote and mismatched totals. See [troubleshooting](https://partners.zayuno.uz/docs/troubleshooting-faq.md) and [actions](https://partners.zayuno.uz/docs/actions.md).\n"
    },
    {
      "id": "actions",
      "title": "Buyurtma lifecycle",
      "file": "actions.md",
      "group": "Contract v1",
      "summary": "Tasdiqdan keyingi action, idempotency va holatlar.",
      "keywords": "order action create cancel status confirmation idempotency",
      "url": "https://partners.zayuno.uz/docs/actions/",
      "markdownUrl": "https://partners.zayuno.uz/docs/actions.md",
      "markdown": "# Actions & Execution Lifecycle\n\nAn action is a confirmed real-world operation sent to a provider. For food ordering, it represents the provider order and its fulfillment state.\n\n## Provider endpoints versus Core endpoints\n\nImplement POST /actions and GET /actions/:id on the provider backend. ACTION_CANCEL adds POST /actions/:id/cancel. Core orchestration routes such as POST /api/v1/actions belong to Zayuno.\n\nUse [canonical action request and response](https://partners.zayuno.uz/docs/contract-reference.md#contract-actions), [status response](https://partners.zayuno.uz/docs/contract-reference.md#contract-action-status), and [OpenAPI](https://partners.zayuno.uz/openapi.json). Do not infer field or enum names from a UI label.\n\n## Preconditions\n\n1. Resolve real catalog IDs, variants, options and quantities.\n2. Obtain a server-calculated quote for that selection and fulfillment.\n3. Verify the quote is still valid.\n4. Obtain explicit customer confirmation of the current price and terms.\n5. Create the action with a persistent idempotencyKey.\n\nChanging the selection or expired terms requires a new quote and confirmation. User contact details alone do not mean the user has confirmed a purchase.\n\n## Normalized statuses\n\nUse the NormalizedAction schema's status enum: CREATED, AWAITING_PAYMENT, CONFIRMED, PROCESSING, COMPLETED, CANCELLED and FAILED.\n\nMap the merchant's internal statuses at the adapter boundary. The Core dashboard may display operational statuses such as SUBMITTED or IN_PROGRESS; those are not a replacement for the provider contract enum. The allowed transition depends on the current action and provider operation.\n\n## Payment evidence is separate\n\nProvider dashboards display paymentStatus separately from action status. PAID is labelled **PROVIDER_REPORTED**: it represents the provider integration's status report, not independent proof of bank settlement.\n\nReturn the provider-owned checkout via nextAction when needed. See [payment handoff](https://partners.zayuno.uz/docs/payment-handoff.md) and [Provider Operations Dashboard and Moderation](https://partners.zayuno.uz/docs/provider-operations.md).\n\n## Idempotency and retries\n\nPersist the incoming idempotencyKey with the created order. Concurrent duplicates and retries after a restart must return the existing action instead of creating another order.\n\nOn an uncertain timeout, query the existing action or retry the same key. Do not generate a fresh key simply because the first response was lost. [Idempotency guide](https://partners.zayuno.uz/docs/errors.md).\n\n## Cancellation and status updates\n\nWhen ACTION_CANCEL is supported, use the canonical cancellation route and payload. A stable reasonCode and safe human-readable reason help explain the result.\n\nCancellation responses always use Zayuno's public reference in `actionId`. If a provider has its own identifier, it is returned separately as `externalActionId`; never substitute it into `actionId`.\n\nProvider sends signed status events to Zayuno's webhook endpoint. Polling GET /actions/:id must reflect the same order identity and authoritative state. Cancellation, payment and fulfillment should remain consistent.\n"
    },
    {
      "id": "payment-handoff",
      "title": "To‘lovga yo‘naltirish",
      "file": "payment-handoff.md",
      "group": "Contract v1",
      "summary": "Provider checkout, nextAction va to‘lov holati.",
      "keywords": "payment checkout nextaction open_url paid",
      "url": "https://partners.zayuno.uz/docs/payment-handoff/",
      "markdownUrl": "https://partners.zayuno.uz/docs/payment-handoff.md",
      "markdown": "# Payment Handoff & NextAction\n\n**Zayuno does not process card payments in this contract.** The provider owns checkout, acquiring, receipts and payment verification.\n\n## Action response\n\nWhen payment is required, return the appropriate normalized action status and nextAction with a provider-owned checkout URL. Use [canonical action response](https://partners.zayuno.uz/docs/contract-reference.md#contract-actions) and [OpenAPI](https://partners.zayuno.uz/openapi.json) for the complete NextAction schema.\n\nDo not assume every NextAction type requires the same fields. Do not manufacture a payment URL or mark an action paid before the provider has verified it.\n\n## Customer flow\n\n1. Customer confirms the quote.\n2. Zayuno creates the action with a stable idempotency key.\n3. Provider returns the actual status and nextAction.\n4. Customer opens the provider checkout and completes payment there.\n5. Provider verifies payment and sends a signed status webhook to Zayuno.\n6. Zayuno displays the resulting action and payment status.\n\nA click on the checkout link is not proof of payment.\n\n## Payment status evidence\n\nDashboard paymentStatus is labelled PROVIDER_REPORTED. It reflects the provider integration's report, not a separate guarantee of bank settlement. Action fulfillment and payment status are separate concepts.\n\nIf checkout expires, show the actual provider state and supported next step. Do not create a second order just to generate another payment link without checking the existing action.\n\n## Optional payment options\n\nWhen PAYMENT_OPTIONS is declared, implement GET /actions/:id/payment-options and return the canonical **top-level array**. See [payment-options reference](https://partners.zayuno.uz/docs/contract-reference.md#contract-payment-options) and [webhooks](https://partners.zayuno.uz/docs/webhooks.md).\n"
    },
    {
      "id": "webhooks",
      "title": "Webhook va eventlar",
      "file": "webhooks.md",
      "group": "Contract v1",
      "summary": "Providerdan Zayunoga imzolangan status xabarlari.",
      "keywords": "hmac callback webhook delivery signature event rawbody",
      "url": "https://partners.zayuno.uz/docs/webhooks/",
      "markdownUrl": "https://partners.zayuno.uz/docs/webhooks.md",
      "markdown": "# Webhooks & asynchronous events\n\nProvider buyurtma holati o‘zgarganda Zayunoga imzolangan event yuboradi. Provider action ID, event ID va status haqiqiy ma’lumotlardan olinadi.\n\n## Canonical endpoint\n\n~~~text\nPOST https://api.zayuno.uz/api/v1/webhooks/{providerSlug}\nContent-Type: application/json\nx-zayuno-signature: <HMAC_SHA256_HEX>\n~~~\n\nproviderSlug URL ichida beriladi. Event ichidagi providerSlug ham shu providerga tegishli bo‘lsin. Yangi integratsiyalar canonical route’dan foydalanadi.\n\n## Event schema va namuna\n\nAniq JSON, required fieldlar va response [generated webhook reference](https://partners.zayuno.uz/docs/contract-reference.md#contract-webhooks) ichida.\n\n- eventId: shu hodisa uchun barqaror ID; retry’da almashtirmang.\n- eventType: contractga mos event turi.\n- providerSlug: ro‘yxatdan o‘tgan provider.\n- actionId yoki externalActionId: to‘g‘ri buyurtmani aniqlash uchun.\n- timestamp: hodisa vaqti, ISO 8601.\n- newStatus va newPaymentStatus: o‘zgarayotgan normalized holatlar.\n\nFaqat backend tasdiqlagan statusni yuboring. To‘lov uchun PAID qiymati provider xabari hisoblanadi; u bank settlement’i mustaqil tekshirilganini anglatmaydi.\n\n## Raw body va HMAC\n\nHMAC-SHA256 hex digest’ni ZAYUNO_WEBHOOK_SECRET bilan **aynan yuboriladigan rawBody** ustida hisoblang. x-zayuno-signature headerga yozing. Timestampni signature stringiga qo‘shmang. [Tayyor TypeScript signing misoli](https://partners.zayuno.uz/docs/auth.md).\n\n## Delivery va retry\n\nHTTP natijasini tekshiring. Timeout yoki vaqtinchalik server xatosida o‘sha eventId bilan cheklangan backoff retry qiling. 401 da key va imzoni tuzatmasdan doimiy retry qilmang.\n\nEvent statusi o‘zgarsa yangi eventId bering. Bir xil eventni qayta yuborish takroriy buyurtma yaratmasligi kerak. Idempotency event va action darajasida alohida ahamiyatga ega.\n\n## Certification talabi va buyurtmaga qo‘llanilishi (isProcessed)\n\nTransactional providerlar certificationdan o‘tishi uchun faqatgina lokal HMAC tekshiruvini bilishi yetarli emas. Avtomatlashtirilgan runner quyidagilarni tekshiradi:\n1. `POST /actions` orqali yaratilgan har bir test buyurtmasi uchun provider backend Zayunoga `action.status_updated` webhookini jo‘natishi kerak.\n2. Zayuno webhookni qabul qilib, imzosi to‘g‘ri ekanligini tasdiqlaydi (`isVerified: true`) va bazadagi test buyurtmasining statusini yangilaydi (`isProcessed: true`).\n3. Faqat `isProcessed: true` bo‘lgan webhooklargina certification runner tomonidan muvaffaqiyatli yetkazib berish va qayta ishlash dalili sifatida qabul qilinadi.\n\n## Diagnostika\n\n[So‘rovlar jurnali](https://partners.zayuno.uz/?tab=inspector) va [troubleshooting](https://partners.zayuno.uz/docs/troubleshooting-faq.md) yordamida provider slug, trace ID, signature header nomi va timestamp’ni tekshiring. Raw secretlarni diagnostika xabariga qo‘shmang.\n"
    },
    {
      "id": "errors",
      "title": "Xatolar va idempotency",
      "file": "errors-and-idempotency.md",
      "group": "Contract v1",
      "summary": "Retry, duplicate, conflict va xato formatlari.",
      "keywords": "error retry idempotency duplicate 409 500 timeout",
      "url": "https://partners.zayuno.uz/docs/errors/",
      "markdownUrl": "https://partners.zayuno.uz/docs/errors.md",
      "markdown": "# Errors & Idempotency\n\nExplicit failures and persistent idempotency prevent duplicate transactions when clients, agents or networks retry.\n\n## Error contract\n\nUse the ErrorResponse schema in [OpenAPI](https://partners.zayuno.uz/openapi.json). Provider and Core errors may have different HTTP wrappers; do not assume a generic NestJS error object is an RFC 7807 problem response.\n\nReturn a safe, actionable message and the appropriate code. Do not expose secrets, full customer data or internal stack traces.\n\n## Action idempotency\n\nEvery create-action request carries an idempotencyKey.\n\n1. Store the key and associated action durably with a unique database constraint.\n2. Make duplicate detection and order creation atomic.\n3. A retry with the same key returns the existing action instead of creating or charging again.\n4. An incompatible payload for an already used key must not silently mutate the original order.\n5. Keep the behavior across process restarts and concurrent requests.\n\nAn in-memory map or cache alone is not sufficient for production order idempotency.\n\n## Retry decisions\n\n| Situation | Next step |\n| --- | --- |\n| Validation failure | Fix the request; do not retry unchanged |\n| Invalid authentication | Fix credentials or signature direction |\n| Expired quote | Obtain a fresh quote and confirmation |\n| Unknown result after timeout | Query status or retry the same idempotency key |\n| Temporary upstream failure | Bounded backoff; preserve request identity |\n| State conflict | Inspect existing action before another mutation |\n\nHTTP status varies by route and failure. Read the structured code and validation report as well as the status. See [troubleshooting](https://partners.zayuno.uz/docs/troubleshooting-faq.md).\n\n## Tests before certification\n\nSend concurrent duplicates, retry after a simulated timeout, restart the backend and resend a key. Verify one provider order exists and the same action ID is returned. Check cancellation and webhook duplicates separately.\n"
    },
    {
      "id": "contract-reference",
      "title": "Provider API reference",
      "group": "Reference",
      "summary": "Koddagi contractdan yaratilgan endpoint va JSON misollar.",
      "keywords": "schema openapi json postman contract endpoint request response",
      "url": "https://partners.zayuno.uz/docs/contract-reference/",
      "markdownUrl": "https://partners.zayuno.uz/docs/contract-reference.md",
      "markdown": "# Provider API reference\n\nContract version: **1.0.0**. This page is generated from `packages/contracts/src/provider-protocol.ts`. Do not edit examples independently.\n\nImplement ZAYUNO_TO_PROVIDER routes on **your provider backend**. The webhook entry is PROVIDER_TO_ZAYUNO. Core management routes live in the separate [Zayuno Core API guide](https://partners.zayuno.uz/docs/api-reference.md).\n\n- [OpenAPI 3.1 JSON](https://partners.zayuno.uz/openapi.json) — schemas, required fields and request/response examples.\n- [Postman collection](https://partners.zayuno.uz/postman.json) — requests with environment placeholders.\n- [Capabilities](https://partners.zayuno.uz/docs/capabilities.md) — read-only vs transactional; physical fulfillment also requires active locations.\n- [Authentication](https://partners.zayuno.uz/docs/auth.md) — outbound auth and inbound webhook signing are separate.\n\nProvider-to-Zayuno status events use `POST https://api.zayuno.uz/api/v1/webhooks/{providerSlug}`.\nNever send production status updates to your own backend URL.\n\n## Request parameters {#contract-parameters}\n\nUse the IDs and field names from the request schema. Base URLs, path parameters and query parameters are not interchangeable. Encode path IDs, send JSON bodies for POST requests, and use the authentication mode selected in the portal.\n\n## GET /provider-info {#contract-metadata}\n\nProvider metadata, advertised capabilities, geography and supported verticals\n\n| Property | Value |\n| --- | --- |\n| Capability | `METADATA` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | DISCOVERY_READONLY, TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | No JSON request body |\n| Response schema | ProviderInfo |\n\n### Request\n\n`GET /provider-info` — no JSON body.\n\n### Response example\n\n```json\n{\n  \"id\": \"provider_shopla\",\n  \"slug\": \"shopla\",\n  \"name\": \"Shopla Online Mart\",\n  \"status\": \"ACTIVE\",\n  \"type\": \"RETAIL\",\n  \"environment\": \"LIVE\",\n  \"category\": \"RETAIL\",\n  \"subcategory\": \"online_marketplace\",\n  \"geography\": [\n    \"UZ\"\n  ],\n  \"adapterType\": \"remote-http\",\n  \"authMethod\": \"API_KEY\",\n  \"capabilities\": [\n    \"METADATA\",\n    \"HEALTH\",\n    \"LOCATIONS\",\n    \"CATALOG\",\n    \"SEARCH\",\n    \"QUOTE\",\n    \"ACTION_CREATE\",\n    \"ACTION_STATUS\",\n    \"PAYMENT_OPTIONS\",\n    \"ACTION_CANCEL\",\n    \"WEBHOOK\"\n  ],\n  \"supportContact\": {\n    \"email\": \"support@shopla.uz\",\n    \"phone\": \"+998712000000\",\n    \"telegram\": \"@shoplasupport\"\n  },\n  \"metadata\": {}\n}\n```\n\nRequired response fields: `id`, `slug`, `name`, `status`, `type`, `capabilities`.\n\n## GET /health {#contract-health}\n\nDeterministic health check protocol with latency and system status\n\n| Property | Value |\n| --- | --- |\n| Capability | `HEALTH` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | DISCOVERY_READONLY, TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | No JSON request body |\n| Response schema | HealthCheckResult |\n\n### Request\n\n`GET /health` — no JSON body.\n\n### Response example\n\n```json\n{\n  \"status\": \"HEALTHY\",\n  \"latencyMs\": 18,\n  \"timestamp\": \"2026-08-24T10:00:00.000Z\",\n  \"details\": {\n    \"uptimeSeconds\": 86400\n  }\n}\n```\n\nRequired response fields: `status`, `latencyMs`, `timestamp`.\n\n## GET /locations {#contract-locations}\n\nPhysical branches, warehouses, pickup locations, or fulfillment centers\n\n| Property | Value |\n| --- | --- |\n| Capability | `LOCATIONS` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | DISCOVERY_READONLY, TRANSACTIONAL |\n| Requirement | When declared; see fulfillment/location requirements |\n| Request schema | No JSON request body |\n| Response schema | Location[] |\n\n### Request\n\n`GET /locations` — no JSON body.\n\n### Response example\n\n```json\n[\n  {\n    \"id\": \"loc_main\",\n    \"providerId\": \"provider_shopla\",\n    \"providerLocationId\": \"branch_1\",\n    \"name\": \"Main Branch\",\n    \"address\": \"Tashkent, Amir Temur 1\",\n    \"latitude\": 41.311081,\n    \"longitude\": 69.240562,\n    \"serviceRadiusKm\": 10,\n    \"isActive\": true,\n    \"metadata\": {}\n  }\n]\n```\n\nRequired response fields: `id`, `providerId`, `providerLocationId`, `name`, `address`.\n\n## GET /catalog {#contract-catalog}\n\nFull catalog hierarchy with categories, offerings, variants, and option groups\n\n| Property | Value |\n| --- | --- |\n| Capability | `CATALOG` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | DISCOVERY_READONLY, TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | No JSON request body |\n| Response schema | Catalog |\n\n### Request\n\n`GET /catalog` — no JSON body.\n\n### Response example\n\n```json\n{\n  \"providerSlug\": \"shopla\",\n  \"categories\": [\n    {\n      \"id\": \"cat_drinks\",\n      \"slug\": \"drinks\",\n      \"title\": \"Ichimliklar\",\n      \"description\": \"Issiq va sovuq ichimliklar\",\n      \"displayOrder\": 1,\n      \"offeringsCount\": 1\n    }\n  ],\n  \"offerings\": [\n    {\n      \"id\": \"item_coffee_latte\",\n      \"providerId\": \"provider_shopla\",\n      \"offeringCode\": \"COFFEE-LATTE\",\n      \"title\": \"Latte\",\n      \"description\": \"Freshly brewed espresso with velvety steamed milk\",\n      \"categorySlug\": \"drinks\",\n      \"categoryTitle\": \"Ichimliklar\",\n      \"basePrice\": 30000,\n      \"currency\": \"UZS\",\n      \"isAvailable\": true,\n      \"variants\": [\n        {\n          \"id\": \"var_standard\",\n          \"name\": \"Standard (300ml)\",\n          \"basePrice\": 30000,\n          \"isAvailable\": true,\n          \"metadata\": {}\n        },\n        {\n          \"id\": \"var_large\",\n          \"name\": \"Large (450ml)\",\n          \"basePrice\": 38000,\n          \"isAvailable\": true,\n          \"metadata\": {}\n        }\n      ],\n      \"optionGroups\": [\n        {\n          \"id\": \"grp_milk\",\n          \"name\": \"Sut turi\",\n          \"isRequired\": false,\n          \"minSelections\": 0,\n          \"maxSelections\": 1,\n          \"options\": [\n            {\n              \"id\": \"opt_whole\",\n              \"name\": \"Oddiy sut\",\n              \"priceDelta\": 0,\n              \"isDefault\": true,\n              \"isAvailable\": true,\n              \"metadata\": {}\n            },\n            {\n              \"id\": \"opt_oat\",\n              \"name\": \"Suli suti (Oat milk)\",\n              \"priceDelta\": 6000,\n              \"isDefault\": false,\n              \"isAvailable\": true,\n              \"metadata\": {}\n            }\n          ]\n        }\n      ],\n      \"tags\": [\n        \"coffee\",\n        \"hot-drinks\"\n      ],\n      \"metadata\": {}\n    }\n  ],\n  \"version\": \"2026.1\",\n  \"updatedAt\": \"2026-08-24T10:00:00.000Z\"\n}\n```\n\nRequired response fields: `providerSlug`, `categories`, `offerings`.\n\n## GET /offerings/:id {#contract-offering}\n\nSingle offering deep lookup by offering ID or offeringCode with option groups\n\n| Property | Value |\n| --- | --- |\n| Capability | `CATALOG` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | DISCOVERY_READONLY, TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | No JSON request body |\n| Response schema | Offering |\n\n### Request\n\n`GET /offerings/:id` — no JSON body.\n\n### Response example\n\n```json\n{\n  \"id\": \"item_coffee_latte\",\n  \"providerId\": \"provider_shopla\",\n  \"offeringCode\": \"COFFEE-LATTE\",\n  \"title\": \"Latte\",\n  \"description\": \"Freshly brewed espresso with velvety steamed milk\",\n  \"categorySlug\": \"drinks\",\n  \"categoryTitle\": \"Ichimliklar\",\n  \"basePrice\": 30000,\n  \"currency\": \"UZS\",\n  \"isAvailable\": true,\n  \"variants\": [\n    {\n      \"id\": \"var_standard\",\n      \"name\": \"Standard (300ml)\",\n      \"basePrice\": 30000,\n      \"isAvailable\": true,\n      \"metadata\": {}\n    },\n    {\n      \"id\": \"var_large\",\n      \"name\": \"Large (450ml)\",\n      \"basePrice\": 38000,\n      \"isAvailable\": true,\n      \"metadata\": {}\n    }\n  ],\n  \"optionGroups\": [\n    {\n      \"id\": \"grp_milk\",\n      \"name\": \"Sut turi\",\n      \"isRequired\": false,\n      \"minSelections\": 0,\n      \"maxSelections\": 1,\n      \"options\": [\n        {\n          \"id\": \"opt_whole\",\n          \"name\": \"Oddiy sut\",\n          \"priceDelta\": 0,\n          \"isDefault\": true,\n          \"isAvailable\": true,\n          \"metadata\": {}\n        },\n        {\n          \"id\": \"opt_oat\",\n          \"name\": \"Suli suti (Oat milk)\",\n          \"priceDelta\": 6000,\n          \"isDefault\": false,\n          \"isAvailable\": true,\n          \"metadata\": {}\n        }\n      ]\n    }\n  ],\n  \"tags\": [\n    \"coffee\",\n    \"hot-drinks\"\n  ],\n  \"metadata\": {}\n}\n```\n\nRequired response fields: `id`, `providerId`, `offeringCode`, `title`, `basePrice`.\n\n## GET /search {#contract-search}\n\nReal-time keyword and parameter search over provider catalog items\n\n| Property | Value |\n| --- | --- |\n| Capability | `SEARCH` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | DISCOVERY_READONLY, TRANSACTIONAL |\n| Requirement | When declared; see fulfillment/location requirements |\n| Request schema | No JSON request body |\n| Response schema | Offering[] |\n\n### Request\n\n`GET /search` — no JSON body.\n\n### Response example\n\n```json\n[\n  {\n    \"id\": \"item_coffee_latte\",\n    \"providerId\": \"provider_shopla\",\n    \"offeringCode\": \"COFFEE-LATTE\",\n    \"title\": \"Latte\",\n    \"description\": \"Freshly brewed espresso with velvety steamed milk\",\n    \"categorySlug\": \"drinks\",\n    \"categoryTitle\": \"Ichimliklar\",\n    \"basePrice\": 30000,\n    \"currency\": \"UZS\",\n    \"isAvailable\": true,\n    \"variants\": [\n      {\n        \"id\": \"var_standard\",\n        \"name\": \"Standard (300ml)\",\n        \"basePrice\": 30000,\n        \"isAvailable\": true,\n        \"metadata\": {}\n      },\n      {\n        \"id\": \"var_large\",\n        \"name\": \"Large (450ml)\",\n        \"basePrice\": 38000,\n        \"isAvailable\": true,\n        \"metadata\": {}\n      }\n    ],\n    \"optionGroups\": [\n      {\n        \"id\": \"grp_milk\",\n        \"name\": \"Sut turi\",\n        \"isRequired\": false,\n        \"minSelections\": 0,\n        \"maxSelections\": 1,\n        \"options\": [\n          {\n            \"id\": \"opt_whole\",\n            \"name\": \"Oddiy sut\",\n            \"priceDelta\": 0,\n            \"isDefault\": true,\n            \"isAvailable\": true,\n            \"metadata\": {}\n          },\n          {\n            \"id\": \"opt_oat\",\n            \"name\": \"Suli suti (Oat milk)\",\n            \"priceDelta\": 6000,\n            \"isDefault\": false,\n            \"isAvailable\": true,\n            \"metadata\": {}\n          }\n        ]\n      }\n    ],\n    \"tags\": [\n      \"coffee\",\n      \"hot-drinks\"\n    ],\n    \"metadata\": {}\n  }\n]\n```\n\nRequired response fields: `id`, `providerId`, `offeringCode`, `title`, `basePrice`.\n\n## POST /quote {#contract-quote}\n\nItemized price calculation with binding total, subtotal, fees and expiration\n\n| Property | Value |\n| --- | --- |\n| Capability | `QUOTE` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | RequestQuoteInput |\n| Response schema | NormalizedQuote |\n\n### Request\n\n```json\n{\n  \"providerSlug\": \"shopla\",\n  \"locationId\": \"loc_main\",\n  \"items\": [\n    {\n      \"offeringId\": \"item_coffee_latte\",\n      \"variantId\": \"var_standard\",\n      \"quantity\": 2,\n      \"selectedOptions\": [\n        {\n          \"groupId\": \"grp_milk\",\n          \"optionId\": \"opt_whole\",\n          \"quantity\": 1\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Response example\n\n```json\n{\n  \"id\": \"quote_123\",\n  \"providerSlug\": \"shopla\",\n  \"locationId\": \"loc_main\",\n  \"currency\": \"UZS\",\n  \"subtotal\": 60000,\n  \"totalFees\": 10000,\n  \"totalDiscount\": 0,\n  \"total\": 70000,\n  \"lines\": [\n    {\n      \"offeringId\": \"item_coffee_latte\",\n      \"offeringTitle\": \"Latte\",\n      \"variantId\": \"var_standard\",\n      \"quantity\": 2,\n      \"unitPrice\": 30000,\n      \"optionsTotal\": 0,\n      \"lineTotal\": 60000,\n      \"selectedOptions\": [\n        {\n          \"groupId\": \"grp_milk\",\n          \"optionId\": \"opt_whole\",\n          \"name\": \"Oddiy sut\",\n          \"priceDelta\": 0\n        }\n      ]\n    }\n  ],\n  \"fees\": [\n    {\n      \"name\": \"Yetkazib berish xizmati\",\n      \"amount\": 10000\n    }\n  ],\n  \"discounts\": [],\n  \"expiresAt\": \"2026-08-24T10:15:00.000Z\",\n  \"metadata\": {}\n}\n```\n\nRequired response fields: `id`, `providerSlug`, `lines`, `subtotal`, `total`, `expiresAt`.\n\n## POST /actions {#contract-actions}\n\nOrder/booking creation with idempotency and provider payment checkout handoff\n\n| Property | Value |\n| --- | --- |\n| Capability | `ACTION_CREATE` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | CreateActionInput |\n| Response schema | NormalizedAction |\n\n### Request\n\n```json\n{\n  \"idempotencyKey\": \"idemp_unique_98765\",\n  \"providerSlug\": \"shopla\",\n  \"quoteId\": \"quote_123\",\n  \"customer\": {\n    \"name\": \"Ali Valiyev\",\n    \"phone\": \"+998901234567\"\n  },\n  \"destination\": {\n    \"raw\": \"Tashkent, Amir Temur 1\"\n  },\n  \"items\": [\n    {\n      \"offeringId\": \"item_coffee_latte\",\n      \"quantity\": 2\n    }\n  ],\n  \"userConfirmed\": true\n}\n```\n\n### Response example\n\n```json\n{\n  \"id\": \"act_12345\",\n  \"publicId\": \"ZY-SHOPLA-12345\",\n  \"externalActionId\": \"ord_provider_999\",\n  \"providerSlug\": \"shopla\",\n  \"quoteId\": \"quote_123\",\n  \"status\": \"AWAITING_PAYMENT\",\n  \"paymentStatus\": \"PENDING\",\n  \"subtotal\": 60000,\n  \"fees\": 10000,\n  \"discount\": 0,\n  \"total\": 70000,\n  \"currency\": \"UZS\",\n  \"customer\": {\n    \"name\": \"Ali Valiyev\",\n    \"phone\": \"+998901234567\"\n  },\n  \"lines\": [\n    {\n      \"offeringId\": \"item_coffee_latte\",\n      \"offeringTitle\": \"Latte\",\n      \"quantity\": 2,\n      \"unitPrice\": 30000,\n      \"optionsTotal\": 0,\n      \"lineTotal\": 60000\n    }\n  ],\n  \"nextAction\": {\n    \"type\": \"OPEN_URL\",\n    \"url\": \"https://checkout.shopla.uz/pay/act_12345\",\n    \"label\": \"Shopla xavfsiz to‘lov sahifasiga o‘tish\"\n  },\n  \"fulfillmentType\": \"STANDARD\",\n  \"createdAt\": \"2026-08-24T10:00:00.000Z\",\n  \"updatedAt\": \"2026-08-24T10:00:00.000Z\",\n  \"metadata\": {}\n}\n```\n\nRequired response fields: `providerSlug`, `quoteId`, `userConfirmed`.\n\n## GET /actions/:id {#contract-action-status}\n\nPolling and real-time status inquiry for created action/order\n\n| Property | Value |\n| --- | --- |\n| Capability | `ACTION_STATUS` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | No JSON request body |\n| Response schema | NormalizedAction |\n\n### Request\n\n`GET /actions/:id` — no JSON body.\n\n### Response example\n\n```json\n{\n  \"id\": \"act_12345\",\n  \"publicId\": \"ZY-SHOPLA-12345\",\n  \"externalActionId\": \"ord_provider_999\",\n  \"providerSlug\": \"shopla\",\n  \"quoteId\": \"quote_123\",\n  \"status\": \"PROCESSING\",\n  \"paymentStatus\": \"PAID\",\n  \"subtotal\": 60000,\n  \"fees\": 10000,\n  \"discount\": 0,\n  \"total\": 70000,\n  \"currency\": \"UZS\",\n  \"customer\": {\n    \"name\": \"Ali Valiyev\",\n    \"phone\": \"+998901234567\"\n  },\n  \"lines\": [\n    {\n      \"offeringId\": \"item_coffee_latte\",\n      \"offeringTitle\": \"Latte\",\n      \"quantity\": 2,\n      \"unitPrice\": 30000,\n      \"optionsTotal\": 0,\n      \"lineTotal\": 60000\n    }\n  ],\n  \"fulfillmentType\": \"STANDARD\",\n  \"createdAt\": \"2026-08-24T10:00:00.000Z\",\n  \"updatedAt\": \"2026-08-24T10:05:00.000Z\",\n  \"metadata\": {}\n}\n```\n\nRequired response fields: `id`, `publicId`, `providerSlug`, `status`, `lines`, `subtotal`, `total`, `createdAt`, `updatedAt`.\n\n## GET /actions/:id/payment-options {#contract-payment-options}\n\nAvailable payment methods discovery for a pending action\n\n| Property | Value |\n| --- | --- |\n| Capability | `PAYMENT_OPTIONS` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | TRANSACTIONAL |\n| Requirement | When declared; see fulfillment/location requirements |\n| Request schema | No JSON request body |\n| Response schema | PaymentOption[] |\n\n### Request\n\n`GET /actions/:id/payment-options` — no JSON body.\n\n### Response example\n\n```json\n[\n  {\n    \"id\": \"pay_click\",\n    \"name\": \"Click\",\n    \"type\": \"CLICK\",\n    \"checkoutUrl\": \"https://checkout.shopla.uz/pay/act_12345?method=click\",\n    \"isAvailable\": true\n  },\n  {\n    \"id\": \"pay_payme\",\n    \"name\": \"Payme\",\n    \"type\": \"PAYME\",\n    \"checkoutUrl\": \"https://checkout.shopla.uz/pay/act_12345?method=payme\",\n    \"isAvailable\": true\n  }\n]\n```\n\nRequired response fields: `id`, `name`, `type`.\n\n## POST /actions/:id/cancel {#contract-cancellation}\n\nAction/order cancellation lifecycle with reason description\n\n| Property | Value |\n| --- | --- |\n| Capability | `ACTION_CANCEL` |\n| Direction | `ZAYUNO_TO_PROVIDER` |\n| Profiles | TRANSACTIONAL |\n| Requirement | When declared; see fulfillment/location requirements |\n| Request schema | CancelActionInput |\n| Response schema | CancelActionResult |\n\n### Request\n\n```json\n{\n  \"reason\": \"Foydalanuvchi buyurtmani bekor qildi\"\n}\n```\n\n### Response example\n\n```json\n{\n  \"success\": true,\n  \"actionId\": \"act_12345\",\n  \"previousStatus\": \"AWAITING_PAYMENT\",\n  \"newStatus\": \"CANCELLED\",\n  \"message\": \"Foydalanuvchi buyurtmani bekor qildi\",\n  \"refundInitiated\": false\n}\n```\n\nRequired response fields: `success`, `actionId`, `previousStatus`, `newStatus`, `message`.\n\n## POST /api/v1/webhooks/:providerSlug {#contract-webhooks}\n\nProvider status update delivery to Zayuno signed with HMAC-SHA256\n\n| Property | Value |\n| --- | --- |\n| Capability | `WEBHOOK` |\n| Direction | `PROVIDER_TO_ZAYUNO` |\n| Profiles | TRANSACTIONAL |\n| Requirement | Required in the listed profiles |\n| Request schema | NormalizedWebhookEvent |\n| Response schema | WebhookIngestionResponse |\n\n### Request\n\n```json\n{\n  \"eventId\": \"evt_123\",\n  \"eventType\": \"action.status_updated\",\n  \"providerSlug\": \"shopla\",\n  \"actionId\": \"act_12345\",\n  \"newStatus\": \"COMPLETED\",\n  \"timestamp\": \"2026-08-24T10:00:00.000Z\"\n}\n```\n\n### Response example\n\n```json\n{\n  \"success\": true\n}\n```\n\nRequired event request fields: `eventId`, `eventType`, `providerSlug`, `timestamp`.\n\n"
    },
    {
      "id": "api-reference",
      "title": "Zayuno Core API",
      "file": "api-reference.md",
      "group": "Reference",
      "summary": "Portal, provider boshqaruvi va Core endpointlar.",
      "keywords": "core api bearer jwt dashboard management endpoint",
      "url": "https://partners.zayuno.uz/docs/api-reference/",
      "markdownUrl": "https://partners.zayuno.uz/docs/api-reference.md",
      "markdown": "# Zayuno Core API Reference\n\nBase URL: `https://api.zayuno.uz/api/v1`\n\n---\n\n## Provider Discovery & Management\n\n### `GET /providers/find`\nDiscover and filter registered capability providers.\n- **Query Parameters**:\n  - `category` *(optional)*: Filter by category (e.g. `food_delivery`, `logistics`, `general_services`).\n  - `capability` *(optional)*: Filter by capability flag (e.g. `ACTION_CREATE`, `LOCATIONS`).\n  - `geography` *(optional)*: Filter by country/region coverage (`UZ`, `Tashkent`).\n  - `query` *(optional)*: Search keyword.\n  - `limit` *(optional)*: Default 20.\n  - `offset` *(optional)*: Default 0.\n\n### `POST /providers/register`\nSelf-serve provider application registration.\n- **Request Body**:\n  ```json\n  {\n    \"name\": \"Acme Logistics\",\n    \"slug\": \"acme-logistics\",\n    \"type\": \"DELIVERY\",\n    \"category\": \"logistics\",\n    \"geography\": [\"UZ\", \"Tashkent\"],\n    \"baseUrl\": \"https://api.acme.example\",\n    \"authMethod\": \"API_KEY\",\n    \"capabilities\": [\"METADATA\", \"HEALTH\", \"CATALOG\", \"QUOTE\", \"ACTION_CREATE\", \"ACTION_STATUS\", \"WEBHOOK\"]\n  }\n  ```\n\n### `POST /providers/:slug/certify`\nExecute automated capability certification suite.\n\n### `POST /providers/:slug/submit-review`\nSubmit certified integration for platform review.\n\n### `GET /providers/me/dashboard`\nReturn provider-scoped metrics and filtered action summaries. Supports\n`query`, `status`, `paymentStatus`, `from`, `to`, `minTotal`, `maxTotal`,\n`sort`, `limit`, and `offset`. The provider scope always comes from the JWT.\n\n### `GET /providers/me/actions/:actionId`\nReturn one action owned by the authenticated provider, including item lines,\nprovider-reported payment status, cancellation reason, and timeline.\n\nSee [Provider Operations Dashboard and Moderation](https://partners.zayuno.uz/docs/provider-operations.md).\n\n### `GET /admin/providers`\nAdmin-only provider list with filters for provider/review status, type,\ncapability, category, geography, certification, owner email, and date range.\nReturns `{ data, total, pagination }`.\n\n### `POST /admin/providers/:slug/review`\nAdmin-only structured moderation decision. Accepts `REQUEST_CHANGES`, `REJECT`,\nor `SUSPEND` plus `reasonCode`, partner-visible `reason`, optional\n`requiredChanges`, and optional operations-only `internalNote`.\n\n### `POST /admin/providers/:slug/reopen`\nAdmin-only operation that reopens a `REJECTED` or `SUSPENDED` application as\n`DRAFT`, invalidates its prior certification, and allows corrections.\n\n### `GET /admin/logs/events`\nAdmin-only redacted operational event stream. See\n[Provider troubleshooting](https://partners.zayuno.uz/docs/troubleshooting-faq.md). Internal operators can also consult the repository document docs/operations-observability.md.\n\n### `GET /admin/logs/export`\nDownload the filtered redacted event stream as `json` or `csv`.\n\n---\n\n## Quotes & Actions\n\n### `POST /quotes`\nCalculate a verified real-time quotation.\n\n### `POST /actions`\nCreate an action with idempotency. Requires `userConfirmed: true`.\n\n### `GET /actions/:id`\nRetrieve live status and fulfillment timeline.\n\n### `POST /actions/:id/cancel`\nCancel an active action.\n\n### `POST /webhooks/:providerSlug`\nCanonical provider-to-Zayuno status event ingestion with HMAC-SHA256 signature verification. Use x-zayuno-signature over the raw body. The legacy slugsiz route is retained for compatibility; new integrations use the slug in the path.\n"
    },
    {
      "id": "certification",
      "title": "Tekshirish va nashr",
      "file": "certification.md",
      "group": "Ishga tushirish",
      "summary": "Sandbox, haqiqiy API certification va review.",
      "keywords": "certify certified sandbox review publish active production test",
      "url": "https://partners.zayuno.uz/docs/certification/",
      "markdownUrl": "https://partners.zayuno.uz/docs/certification.md",
      "markdown": "# API tekshiruvi va universal sertifikatlash (v2 Strict)\n\nCertification ulangan provider backendini universal Provider Contract v1 va Strict qoidalari bilan sinovdan o‘tkazadi. Bu oddiy namunaviy oqim emas, balki real xavfsizlik, narx matematikasi, invaryantlar va webhook yetib borishining avtomatlashtirilgan tekshiruvidir.\n\n## 1. Test turlari va qayerda tekshiriladi?\n\n| Vosita | Nima tekshiriladi | Natija nimani anglatadi |\n| --- | --- | --- |\n| Sandbox | Namunaviy providerda discovery → quote → action | Oqim qanday ishlashini tushunish uchun vizual simulyator |\n| Certification v2 (Strict) | Siz sozlagan haqiqiy provider API | E’lon qilingan barcha capability, manifest va invaryantlarning to‘liq mosligi |\n| Review | Ariza, v2 hisoboti va operatsion talablar | Jonli tizimga (ACTIVE) chiqarish bo‘yicha qaror |\n| Inspector | Provider so‘rovlari va trace’lar | Har bir so‘rov va javobni tahlil qilish vositasi |\n\nTransactional certification haqiqiy test buyurtmasi (action) yaratadi va providerdan imzolangan webhook kutadi. Backendda test katalog va xavfsiz test muhitini sozlang.\n\n## 2. Universal Manifest talablari (`GET /provider-info`)\n\nZayuno har bir providerga bir xil qattiq talablarni (masalan, barchaga telefon yoki ism majburlashni) yuklamaydi. Provider o‘z talablarini `GET /provider-info` dagi `manifest` orqali e’lon qiladi:\n\n1. **Xavfsiz test muhiti (Majburiy):**\n   ```json\n   \"manifest\": {\n     \"version\": 1,\n     \"certification\": {\n       \"safeTestEnvironment\": true\n     }\n   }\n   ```\n   *Agar `manifest.certification.safeTestEnvironment: true` bo‘lmasa, strict certification xavfsizlik nuqtai nazaridan to‘xtatiladi.*\n\n2. **Mijoz talablari (`customerRequirements`):**\n   - Agar xizmat mijoz kontaktini talab qilmasa (masalan, digital API token): `\"customerRequirements\": {}`.\n   - Agar faqat email kerak bo‘lsa (masalan, SaaS litsenziyasi): `\"customerRequirements\": { \"email\": \"REQUIRED\" }`.\n   - Agar telefon va ism kerak bo‘lsa: `\"customerRequirements\": { \"name\": \"REQUIRED\", \"phone\": \"REQUIRED\" }`.\n\n3. **Kirish rejimi (`requirements.QUOTE.inputMode` va `ACTION_CREATE.inputMode`):**\n   - Katalog va offering asosida bo‘lsa: `\"OFFERING\"`.\n   - Faqat parametrlar asosida bo‘lsa (masalan, kommunal to‘lovlar, hisob raqami): `\"PARAMETERS\"`. Bu holatda `\"parametersSchema\"` e’lon qilinishi shart.\n\n4. **Namunaviy test parametrlari (`certificationInput`):**\n   Provider certification runnerga test paytida qaysi namunaviy parametrlar (`customer`, `parameters`, `locations`) bilan so‘rov yuborish kerakligini ko‘rsatadi:\n   ```json\n   \"certificationInput\": {\n     \"customer\": { \"phone\": \"+998901234567\" },\n     \"parameters\": { \"accountNumber\": \"ACC-123456\" }\n   }\n   ```\n\n## 3. Qat’iy tekshiruvlar va rad etish sabablarini ajratish\n\nCertification testlari salbiy holatlarni (adversarial probes) yuborib, backendning to‘g‘ri rad etishini tekshiradi:\n\n- **Noto‘g‘ri sabab bilan rad etish taqiqlangan (Rejection Reason Discrimination):**\n  Yetishmayotgan majburiy maydon tekshirilayotganda backend aynan shu maydon xatoligi bo‘yicha 400 yoki 422 qaytarishi shart (`errorCode: 'VALIDATION_ERROR'` yoki field path ko‘rsatilgan holda). Agar backend begona sabab bilan (masalan, `QUOTE_EXPIRED`, `QUOTE_NOT_FOUND` yoki `ACTION_NOT_CONFIRMED`) rad etsa, test yiqiladi.\n- **Idempotency kaliti to‘qnashuvi:**\n  Bir xil `idempotencyKey` bilan o‘zgargan payload yuborilganda backend HTTP 409 statusi va `errorCode: 'IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD'` qaytarishi shart.\n- **Quote amal qilish muddati (TTL):**\n  Kotirovka kamida 5 soniya amal qilishi kerak, toki action yaratish probe'lari quote muddati o‘tib ketmasdan avval bajarilsin. Muddati o‘tgan quote bilan buyurtma berilganda 410 `QUOTE_EXPIRED` qaytishi kerak.\n- **Faqat tasdiqlangan buyurtmalar (`userConfirmed: true`):**\n  `userConfirmed: false` bo‘lgan so‘rovlar qat’iy rad etilishi shart (`ACTION_NOT_CONFIRMED`).\n\n## 4. Webhook va buyurtma holati o‘tishi (DB Execution Evidence)\n\nTransactional providerlar uchun lokal HMAC algoritmini bilish yetarli emas. Test action yaratilgach:\n1. Provider backend Zayunoning webhook endpointiga imzolangan so‘rov yuborishi shart:\n   `POST https://api.zayuno.uz/api/v1/webhooks/{providerSlug}`\n2. Headerda `x-zayuno-signature` (HMAC-SHA256 hex digest) bo‘lishi lozim.\n3. Event formati: `eventType: 'action.status_updated'`, `actionId` joriy test action ID'siga teng bo‘lishi shart.\n4. Zayuno webhookni qabul qilib, bazadagi buyurtma statusini muvaffaqiyatli yangilashi (`isProcessed: true`) shart. Agar buyurtma bazada topilmasa yoki status o‘tmasa, certification rad etiladi.\n\n## 5. Sertifikat versiyasi va eskirgan hisobotlar\n\n- Faqat **`certificationVersion: 2`** va **`mode: 'STRICT'`** bo‘lgan hisobotgina \"TAYYOR (PRODUCTION READY)\" deb hisoblanadi.\n- Eski (v1) yoki STANDARD hisobotlar Portalda `QAYTA SERTIFIKATLASH TALAB ETILADI (ESKI HISOBOT)` deb ko‘rsatiladi va moderatorga topshirish (`submit-review`) bloklanadi.\n\n## 6. Xatoliklarni diagnostika qilish\n\nXato chiqsa, xatolik kodi va field path'ni tekshiring:\n- `safeTestEnvironment`: Manifestda `certification: { safeTestEnvironment: true }` borligini tekshiring.\n- `disallowed error code`: Majburiy maydon yetishmaganda quote expiry emas, validatsiya xatosi qaytaring.\n- `webhook-delivery`: Provider action yaratilgandan so‘ng `/api/v1/webhooks/:providerSlug` ga `action.status_updated` webhook yuborganini tekshiring.\n- Batafsil yechimlar: [Troubleshooting & FAQ](https://partners.zayuno.uz/docs/troubleshooting-faq.md).\n"
    },
    {
      "id": "provider-operations",
      "title": "Dashboard va operatsiyalar",
      "file": "provider-operations.md",
      "group": "Ishga tushirish",
      "summary": "Buyurtmalar monitoringi, review va provider account.",
      "keywords": "operations orders dashboard metrics changes_requested moderation",
      "url": "https://partners.zayuno.uz/docs/provider-operations/",
      "markdownUrl": "https://partners.zayuno.uz/docs/provider-operations.md",
      "markdown": "# Provider Operations Dashboard and Moderation\n\nThis document is part of the public Zayuno provider contract. Any externally\nvisible change to provider onboarding, action visibility, payment reporting,\nmoderation, or lifecycle rules must update this document and the changelog in\nthe same change set.\n\n## Provider-scoped action dashboard\n\nAuthenticated provider owners, developers, and analysts can use:\n\n```http\nGET /api/v1/providers/me/dashboard\nAuthorization: Bearer <provider-dashboard-jwt>\n```\n\nSupported filters:\n\n| Parameter | Meaning |\n| --- | --- |\n| `query` | Action ID, external action ID, customer name, or phone |\n| `status` | Normalized action status |\n| `paymentStatus` | `PENDING`, `AUTHORIZED`, `PAID`, `FAILED`, or `REFUNDED` |\n| `from`, `to` | ISO date or timestamp range |\n| `minTotal`, `maxTotal` | Non-negative action total range |\n| `sort` | `newest`, `oldest`, `total_asc`, or `total_desc` |\n| `limit`, `offset` | Pagination; limit is capped at 100 |\n\nThe response includes global provider metrics, filtered action summaries, and\npagination. The API always derives the provider ID from the authenticated\naccount. A provider ID supplied by the browser is never trusted.\n\n```json\n{\n  \"metrics\": {\n    \"totalActions\": 32,\n    \"pendingActions\": 4,\n    \"paidActions\": 19,\n    \"completedActions\": 17,\n    \"failedActions\": 2\n  },\n  \"actions\": [\n    {\n      \"publicId\": \"ZY-EXAMPLE-10001\",\n      \"status\": \"IN_PROGRESS\",\n      \"paymentStatus\": \"PAID\",\n      \"paymentStatusSource\": \"PROVIDER_REPORTED\",\n      \"total\": 155000,\n      \"currency\": \"UZS\",\n      \"customerName\": \"Example Customer\",\n      \"customerPhoneMasked\": \"+99890***567\"\n    }\n  ],\n  \"pagination\": { \"total\": 1, \"limit\": 50, \"offset\": 0, \"hasMore\": false }\n}\n```\n\n`PAID` means the provider integration reported that payment state. It does not\nprove bank settlement unless the provider's payment integration explicitly\nsupplies settlement data.\n\n## Provider-scoped action detail\n\n```http\nGET /api/v1/providers/me/actions/:actionId\nAuthorization: Bearer <provider-dashboard-jwt>\n```\n\nThe endpoint accepts a Zayuno public ID, internal action ID, or provider\nexternal action ID. It returns the item lines, normalized action and payment\nstatus, provider-reported payment source, customer fulfillment details,\ncancellation/failure explanation, and chronological timeline. It returns 404\nfor actions belonging to another provider.\n\n## Cancellation and failure reasons\n\nProvider adapters should send a concise, user-safe explanation for terminal\nevents. Prefer a stable machine-readable reason code in the event payload and\na clear human description. Suggested codes include:\n\n- `CUSTOMER_CANCELLED`\n- `PROVIDER_REJECTED`\n- `ITEM_UNAVAILABLE`\n- `PAYMENT_TIMEOUT`\n- `PAYMENT_FAILED`\n- `DUPLICATE_ACTION`\n- `INVALID_CUSTOMER_INFORMATION`\n- `PROVIDER_TIMEOUT`\n- `SYSTEM_ERROR`\n- `OTHER`\n\nDo not place secrets, card data, passwords, OTP values, or unnecessary identity\ndocuments in a reason or timeline description.\n\n## Moderation lifecycle\n\n```text\nDRAFT -> PENDING_APPROVAL -> APPROVED -> ACTIVE\n                     |-> CHANGES_REQUESTED -> DRAFT -> PENDING_APPROVAL\n                     |-> REJECTED\nACTIVE --------------------------------------> SUSPENDED\n```\n\nEvery non-approval decision requires:\n\n- `reasonCode`: stable category;\n- `reason`: partner-visible explanation (minimum 12 characters);\n- `requiredChanges`: actionable checklist when applicable;\n- `internalNote`: optional operations-only note.\n\nPartner-visible reasons are returned in provider metadata. Review history and\ninternal notes are kept only for operations and must never be exposed by public\ndiscovery endpoints. Resubmitting an integration clears the current visible\nreason while preserving the audit history.\n\n`CHANGES_REQUESTED` applications may update their integration and resubmit.\n`REJECTED` or `SUSPENDED` applications cannot reset themselves to `DRAFT` by\nediting the base URL; Operations must explicitly reopen them.\n\n```http\nPOST /api/v1/admin/providers/:slug/reopen\nAuthorization: Bearer <admin-jwt>\n```\n\n## Operations provider filters\n\nThe admin endpoint supports filtering by query, provider status, review status,\nprovider type, capability, category, geography, certification state, owner\nemail, and registration date range:\n\n```http\nGET /api/v1/admin/providers?reviewStatus=PENDING_APPROVAL&certified=true\nAuthorization: Bearer <admin-jwt>\n```\n\nThe response is `{ data, total, pagination }`.\n\n## Documentation rule\n\nThe following changes require documentation and changelog updates in the same\npull request or release bundle:\n\n- public API request or response changes;\n- MCP tool or capability changes;\n- provider onboarding and certification changes;\n- action, payment, cancellation, or moderation lifecycle changes;\n- dashboard workflows that providers depend on.\n\nRun `pnpm test:docs-contract` before release. Internal refactors that do not\nchange observable behavior do not require a public contract update.\n"
    },
    {
      "id": "troubleshooting-faq",
      "title": "Muammoni topish · FAQ",
      "file": "troubleshooting-faq.md",
      "group": "Ishga tushirish",
      "summary": "CORS, 401, HMAC, quote math va timeout yechimlari.",
      "keywords": "troubleshooting error cors 401 403 500 hmac timeout rawbody fail",
      "url": "https://partners.zayuno.uz/docs/troubleshooting-faq/",
      "markdownUrl": "https://partners.zayuno.uz/docs/troubleshooting-faq.md",
      "markdown": "# Troubleshooting & FAQ\n\nStart with the request direction, provider slug, HTTP status, trace ID and validation field path. Open the [Inspector](https://partners.zayuno.uz/?tab=inspector) for provider requests. Do not paste unredacted headers into a support ticket.\n\n## 401: credentials and HMAC\n\n| Request | Expected credential |\n| --- | --- |\n| Zayuno → provider, API_KEY mode | x-provider-api-key |\n| Zayuno → provider, BEARER_TOKEN mode | Authorization: Bearer |\n| Zayuno → provider, HMAC_SIGNATURE mode | x-zayuno-signature over rawBody |\n| Provider → Zayuno webhook | x-zayuno-signature with ZAYUNO_WEBHOOK_SECRET |\n| Portal → Zayuno Core | Account access token |\n\nA provider API key is not a webhook signing secret. Confirm the portal's authMethod matches the backend. After secret rotation update both sides.\n\nFor rawBody verification, use exactly the bytes sent over HTTP; parsing and reserializing JSON can change whitespace and field order. Current signing does not prepend a timestamp. See [authentication](https://partners.zayuno.uz/docs/auth.md) for a signing example.\n\n## CORS & Preflight\n\nZayuno's normal provider API calls are server-to-server. CORS does not authorize those calls and is not a replacement for API authentication.\n\nIf your own browser-based development tool calls your backend, allow only its actual origin and required headers. The provider portal origin is https://partners.zayuno.uz. Handle OPTIONS if your tool uses preflight. Do not move production provider secrets into browser code to solve a CORS error.\n\n## 404 or HTML instead of JSON\n\nCheck the configured base URL. For https://YOUR_HOST/zayuno, health resolves to https://YOUR_HOST/zayuno/health.\n\n- Do not use the portal's frontend URL.\n- Do not append /health to the base URL.\n- Do not implement Core /api/v1/quotes where the provider expects POST /quote.\n- Check reverse proxy prefixes and trailing slashes.\n\n[Base URL guide](https://partners.zayuno.uz/docs/base-url.md) includes Express and FastAPI starting points.\n\n## Latency & Timeout\n\nVerify the backend is reachable from the hosted service, not only from your laptop. localhost and private IP addresses are not reachable provider hosts for hosted Zayuno. Use a public HTTPS test endpoint.\n\nInspect provider logs for slow database queries, downstream API delays and retries. A timeout after action creation has an unknown result; retry with the same idempotencyKey or query status, not a new key.\n\nDo not return fake HEALTHY or successful actions to hide a timeout.\n\n## Quote Math Validation\n\nCalculate prices on the provider server from real catalog and selected variants/options.\n\n~~~text\nsubtotal = sum(lines[].lineTotal)\ntotal = subtotal + totalFees - totalDiscount\n~~~\n\nReturn canonical id and lines, currency and expiresAt. Do not use only quoteId or items in new normalized responses. Quantity, option counts and decimal handling must match the contract. Do not recalculate totals in the client to disguise mismatched provider data.\n\nWhen a quote expires or selections change, request a new quote and get confirmation for its terms before creating an action. [Quote reference](https://partners.zayuno.uz/docs/contract-reference.md#contract-quote).\n\n## Capability or location failure\n\nREADONLY requires METADATA, HEALTH, CATALOG. Transactional integrations additionally require QUOTE, ACTION_CREATE, ACTION_STATUS, WEBHOOK.\n\nPhysical fulfillment (DELIVERY, PICKUP, ONSITE, HYBRID) requires active locations. Removing LOCATIONS from declared capabilities does not remove this requirement. See [capability profiles](https://partners.zayuno.uz/docs/capabilities.md).\n\n## Common diagnostic codes\n\n| Code / signal | Next step |\n| --- | --- |\n| UNAUTHORIZED / 401 | Match auth method, credential and signature direction |\n| NOT_FOUND / 404 | Check base URL, endpoint and real resource ID |\n| QUOTE_MATH_INVALID | Reconcile lines, fees, discounts and total |\n| Quote expired / state conflict | Get a fresh quote or inspect existing action before retry |\n| RESERVED_BRAND_PROTECTED | Use the authorized business identity; contact operations for an existing protected brand |\n| CHANGES_REQUESTED | Read review notes and requiredChanges in the dashboard |\n| Schema field path | Compare that field with generated OpenAPI; do not rename guessed fields |\n| Timeout / upstream failure | Check public reachability, server logs and downstream dependencies |\n\nHTTP mappings depend on the route and failure; use the returned code and report instead of assuming every failure has one fixed status.\n\n## Certification v2 (Strict) xatolari va yechimlari\n\n### 1. `Provider manifest must explicitly declare manifest.certification.safeTestEnvironment = true`\n- **Sababi:** Provider o‘z backendida test harakatlarini xavfsiz qabul qila olishini tasdiqlamagan.\n- **Yechim:** `GET /provider-info` javobidagi `manifest` obyektiga `\"certification\": { \"safeTestEnvironment\": true }` maydonini qo‘shing.\n\n### 2. `Provider rejected with disallowed error code (e.g. QUOTE_EXPIRED, QUOTE_NOT_FOUND, ACTION_NOT_CONFIRMED)`\n- **Sababi:** Test majburiy maydon yo‘qligini (masalan, `customer.phone`) tekshirayotganda, backend kutilgan validatsiya xatosi o‘rniga quote muddati o‘tgani yoki action tasdiqlanmaganini bahona qilib rad etdi.\n- **Yechim:** So‘rov body’si parametrlarini tekshirishni (input validation) quote expiry yoki boshqa biznes mantiqlaridan oldin bajaring. Majburiy maydon bo‘lmasa HTTP 400 yoki 422 bilan `VALIDATION_ERROR` qaytaring.\n\n### 3. `No verified action status webhook was received for the current certification action`\n- **Sababi:** `action-create` testi muvaffaqiyatli buyurtma yaratgandan so‘ng, provider backend Zayunoga buyurtma holati yangilanganligi haqida imzolangan webhook yubormadi yoki webhook yetib bormadi.\n- **Yechim:**\n  - Action yaratilgach, backenddan `POST https://api.zayuno.uz/api/v1/webhooks/{providerSlug}` ga so‘rov yuboring.\n  - Headerda `x-zayuno-signature` (portal bergan `webhookSecret` bilan hisoblangan HMAC-SHA256 hex digest) bo‘lishi shart.\n  - Payload formati: `{ \"eventId\": \"evt-123\", \"eventType\": \"action.status_updated\", \"providerSlug\": \"{providerSlug}\", \"actionId\": \"{actionId}\", \"newStatus\": \"CONFIRMED\", \"timestamp\": \"...\" }`.\n\n### 4. `Webhook signature valid but isProcessed: false`\n- **Sababi:** Webhook Zayunoga yetib borgan va imzosi to‘g‘ri, ammo bazadagi action statusi yangilanmagan (masalan, `actionId` noto‘g‘ri yoki mavjud bo‘lmagan status ko‘rsatilgan).\n- **Yechim:** Webhook payloadidagi `actionId` Zayuno `POST /actions` so‘rovida olgan `id` bilan bir xil ekanligiga va `newStatus` `CONFIRMED` kabi standart ActionStatus qiymati ekanligiga ishonch hosil qiling.\n\n### 5. `QAYTA SERTIFIKATLASH TALAB ETILADI (ESKI HISOBOT)`\n- **Sababi:** Mavjud sertifikat v1 yoki STANDARD diagnostika rejimida olingan bo‘lib, Strict v2 talablariga javob bermaydi.\n- **Yechim:** Portalda 3-bosqichga (Sertifikatlash) o‘ting va \"Qayta sertifikatlash\" tugmasini bosing. STRICT rejimida muvaffaqiyatli o‘tgach, \"Ko‘rib chiqishga topshirish\" tugmasi faollashadi.\n\n## Sandbox works but certification fails\n\nThe portal sandbox uses a sample provider. It proves the example flow works, not that your backend implements the contract.\n\nCertification runs your configured adapter. Check providerSlug, base URL, capabilities and test data. It may create a test action for transactional integrations. A passing certification is still separate from approval and ACTIVE status.\n\n## What should an AI agent receive?\n\nGive the agent the [canonical workflow](https://partners.zayuno.uz/docs/ai-agents.md), contract version, framework, capability profile and redacted failure. AI Kit can include the certification context. Ask it to report changed files, tests, remaining work and the exact next step.\n"
    }
  ]
}