{"openapi":"3.1.0","info":{"title":"ZangAI Partner API","version":"0.1.0","description":"Публичный REST API ZangAI для партнёрских интеграций (ТЗ раздел 7). Авторизация — заголовок X-Api-Key; ключ выдаётся в кабинете и несёт явный набор прав — эндпоинт, для которого у ключа нет нужного права, отвечает 403 (право отсутствует), а не 404 (эндпоинт спрятан): партнёр, подключающийся по этой спеке, обязан видеть все существующие публичные операции независимо от того, какими правами наделён его собственный ключ. Ошибки — RFC7807 (application/problem+json) с полем request_id. Эта поверхность документирована и версионируется отдельно от кабинета — внутренние эндпоинты сюда не попадают, партнёр подключается по ней самостоятельно, без участия платформы (гейт G3)."},"paths":{"/api/v1/leads":{"post":{"tags":["leads","partner-api"],"summary":"Приём лида — главный вход speed-to-lead (ТЗ 7.1, US-7)","description":"Принять лид от партнёра и поставить звонок в очередь speed-to-lead.\n\nГлавный вход воронки продаж (ТЗ 7.1, US-7): звонок обязан начаться в\nсреднем не позже 60 секунд после заявки в окне 09:00–18:00. Вне окна\nзвонок планируется на ближайшее открытие, а контакту сразу уходит\nчат-сообщение (`action=\"chat_sent_call_scheduled\"`).\n\nИдемпотентен по `external_id` (ТЗ 7.1 дословно): повторная отправка той\nже заявки (сеть партнёра ретраит без гарантии «доставлено ровно один\nраз») возвращает результат ПЕРВОЙ обработки и не ставит второй звонок.\n\nСогласие (`consent`), если передано, фиксируется как append-only\nдоказательство (FR-L.5) и участвует в решении комплаенса\n(`ComplianceGate`) вместе с DNC — единого списка отказа для звонков и\nчатов (CLAUDE.md, правило 4). Комплаенс блокирует постановку в очередь,\nа не предупреждает (правило 3): заблокированная заявка отвечает\n`action=\"blocked_dnc\"`/`\"blocked_compliance\"`, а не 4xx — она принята и\nсохранена, просто звонок по ней не будет поставлен.","operationId":"create_lead_api_v1_leads_post","parameters":[{"name":"X-Api-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadOut"}}}},"401":{"description":"Заголовок X-Api-Key отсутствует, либо ключ не найден/отозван.","content":{"application/problem+json":{"schema":{"description":"Тело ответа об ошибке в формате RFC 7807.","properties":{"type":{"default":"about:blank","description":"URI, идентифицирующий тип проблемы (about:blank, если специфичного нет).","title":"Type","type":"string"},"title":{"description":"Короткое человекочитаемое описание типа проблемы.","title":"Title","type":"string"},"status":{"description":"HTTP-статус ответа (дублирует статус-код HTTP).","title":"Status","type":"integer"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Детали конкретного случая ошибки.","title":"Detail"},"instance":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Путь запроса, в котором произошла ошибка.","title":"Instance"},"request_id":{"description":"Идентификатор запроса (см. заголовок X-Request-Id) для трассировки.","title":"Request Id","type":"string"}},"required":["title","status","request_id"],"title":"ProblemDetail","type":"object"}}}},"403":{"description":"Ключ действителен, но не наделён правом leads:write (ТЗ FR-I.4 — права на ключ, а не только его валидность).","content":{"application/problem+json":{"schema":{"description":"Тело ответа об ошибке в формате RFC 7807.","properties":{"type":{"default":"about:blank","description":"URI, идентифицирующий тип проблемы (about:blank, если специфичного нет).","title":"Type","type":"string"},"title":{"description":"Короткое человекочитаемое описание типа проблемы.","title":"Title","type":"string"},"status":{"description":"HTTP-статус ответа (дублирует статус-код HTTP).","title":"Status","type":"integer"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Детали конкретного случая ошибки.","title":"Detail"},"instance":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Путь запроса, в котором произошла ошибка.","title":"Instance"},"request_id":{"description":"Идентификатор запроса (см. заголовок X-Request-Id) для трассировки.","title":"Request Id","type":"string"}},"required":["title","status","request_id"],"title":"ProblemDetail","type":"object"}}}},"409":{"description":"Тенант ещё не настроил сценарий агента, принимающего этот лид — ошибка конфигурации тенанта, лид при этом уже сохранён (идемпотентен по external_id при повторной отправке).","content":{"application/problem+json":{"schema":{"description":"Тело ответа об ошибке в формате RFC 7807.","properties":{"type":{"default":"about:blank","description":"URI, идентифицирующий тип проблемы (about:blank, если специфичного нет).","title":"Type","type":"string"},"title":{"description":"Короткое человекочитаемое описание типа проблемы.","title":"Title","type":"string"},"status":{"description":"HTTP-статус ответа (дублирует статус-код HTTP).","title":"Status","type":"integer"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Детали конкретного случая ошибки.","title":"Detail"},"instance":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Путь запроса, в котором произошла ошибка.","title":"Instance"},"request_id":{"description":"Идентификатор запроса (см. заголовок X-Request-Id) для трассировки.","title":"Request Id","type":"string"}},"required":["title","status","request_id"],"title":"ProblemDetail","type":"object"}}}},"422":{"description":"Тело запроса не прошло валидацию — например, phone не в формате E.164 (+код страны и 8-15 цифр).","content":{"application/problem+json":{"schema":{"description":"Тело ответа об ошибке в формате RFC 7807.","properties":{"type":{"default":"about:blank","description":"URI, идентифицирующий тип проблемы (about:blank, если специфичного нет).","title":"Type","type":"string"},"title":{"description":"Короткое человекочитаемое описание типа проблемы.","title":"Title","type":"string"},"status":{"description":"HTTP-статус ответа (дублирует статус-код HTTP).","title":"Status","type":"integer"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Детали конкретного случая ошибки.","title":"Detail"},"instance":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Путь запроса, в котором произошла ошибка.","title":"Instance"},"request_id":{"description":"Идентификатор запроса (см. заголовок X-Request-Id) для трассировки.","title":"Request Id","type":"string"}},"required":["title","status","request_id"],"title":"ProblemDetail","type":"object"}}}},"429":{"description":"Превышен лимит частоты приёма лидов для этого тенанта (20 запросов за 60 с).","content":{"application/problem+json":{"schema":{"description":"Тело ответа об ошибке в формате RFC 7807.","properties":{"type":{"default":"about:blank","description":"URI, идентифицирующий тип проблемы (about:blank, если специфичного нет).","title":"Type","type":"string"},"title":{"description":"Короткое человекочитаемое описание типа проблемы.","title":"Title","type":"string"},"status":{"description":"HTTP-статус ответа (дублирует статус-код HTTP).","title":"Status","type":"integer"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Детали конкретного случая ошибки.","title":"Detail"},"instance":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Путь запроса, в котором произошла ошибка.","title":"Instance"},"request_id":{"description":"Идентификатор запроса (см. заголовок X-Request-Id) для трассировки.","title":"Request Id","type":"string"}},"required":["title","status","request_id"],"title":"ProblemDetail","type":"object"}}}}}}}},"tags":[{"name":"leads","description":"Приём лида — главный вход speed-to-lead (ТЗ 7.1, US-7)."}],"components":{"schemas":{"LeadOut":{"properties":{"lead_id":{"type":"string","format":"uuid","title":"Lead Id"},"contact_id":{"type":"string","format":"uuid","title":"Contact Id"},"action":{"$ref":"#/components/schemas/LeadAction"},"eta_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Eta Seconds"},"scheduled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled At"}},"type":"object","required":["lead_id","contact_id","action"],"title":"LeadOut","description":"Ответ ТЗ 7.1: `{lead_id, contact_id, action, eta_seconds}` в окне,\n`{..., action, scheduled_at}` вне окна (см. `response_model_exclude_none`\nу роута — пустое поле не попадает в JSON)."},"LeadIn":{"properties":{"phone":{"type":"string","title":"Phone"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Id"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"},"consent":{"anyOf":[{"$ref":"#/components/schemas/ConsentIn"},{"type":"null"}]}},"type":"object","required":["phone"],"title":"LeadIn","description":"Тело `POST /api/v1/leads` — ровно контракт ТЗ 7.1.","example":{"consent":{"evidence_uri":"https://example.uz/forms/42","kind":"lead_form"},"external_id":"fb_123","name":"Aziza","note":"интересует IELTS","phone":"+998901234567","source":"instagram_ads"}}}}}