> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tungo.kz/llms.txt
> Use this file to discover all available pages before exploring further.

# Завести адрес

> Адрес — только https и не во внутренней сети (localhost, 10.x, 192.168.x, 169.254.x… — и по DNS тоже); сервер доставки ещё раз проверяет это при каждой отправке. event_types — фильтр событий (null или нет — все). channels — id сценариев (scn_…): только их события, например итог сценария в CRM магазина. Сколько адресов можно — настройка платформы webhooks.max_endpoints_per_workspace (сверх — 429, code webhook_endpoints_limit). Одновременные заведения в одной организации идут по очереди; если другой адрес заводится дольше нескольких секунд — 503 (code webhooks_unavailable), повторить позже. Секрет подписи — в ответе.

Idempotency-Key: повтор с тем же ключом и тем же телом отдаёт прежний ответ (статус и тело) с заголовком Idempotent-Replayed: true и ничего не делает второй раз; тот же ключ с другим адресом или телом — 422 (error.code = idempotency_key_reused); первый запрос с этим ключом ещё идёт — 409 (error.code = idempotency_in_progress). Запоминается только удачный ответ (2xx): после отказа повтор с тем же ключом выполнится заново. Ключ живёт сутки (настройка idempotency.keys), область — организация и тот, кто прислал (ключ API или человек).

Доступ: Владелец или админ workspace; ключ API — с правом webhooks.manage.

Доступно по ключу API.



## OpenAPI

````yaml https://api.tungo.kz/v1/openapi.json post /v1/workspaces/{ws}/webhooks/endpoints
openapi: 3.1.0
info:
  title: Tungo Platform API
  version: 0.1.0
  description: >-
    ## Быстрый старт


    От ключа до первого ответа и проверки подписи вебхука. Суммы — в тиынах (1 ₸
    = 100 тиын).


    ```sh

    export TUNGO_API=<адрес из раздела servers этого описания>

    export TUNGO_KEY=tg_…   # шаг 1

    export WS=ws_…          # шаг 2

    export CO=co_…          # шаг 2

    ```


    ### 1. Получить ключ


    Ключ выпускает владелец или админ организации, войдя в кабинет: POST
    /v1/workspaces/{ws}/api-keys. По ключу этот адрес не работает. В теле —
    `name`, `company_ids` и `permissions`. Для примеров ниже нужны права
    `chat.use` и `webhooks.manage`; второе — только у ключа на все компании
    организации. Ключ целиком (`key`) показывается один раз. Держите его на
    своём сервере: из браузера API не вызывается.


    ### 2. Проверить ключ и узнать id


    ```sh

    curl "$TUNGO_API/v1/api-key" -H "x-api-key: $TUNGO_KEY"

    curl "$TUNGO_API/v1/companies" -H "x-api-key: $TUNGO_KEY"

    ```


    Id организации — `workspace` → `id` в первом ответе; id компаний — `data` →
    `id` во втором. Вместо `x-api-key` можно передать `Authorization: Bearer
    tg_…`.


    ### 3. Проверить баланс и цены


    У платформы свой баланс, отдельно от подписки чата.


    ```sh

    curl "$TUNGO_API/v1/workspaces/$WS/platform/account" -H "x-api-key:
    $TUNGO_KEY"

    curl "$TUNGO_API/v1/usage-rates"

    ```


    Первый ответ — `balance_tiyn`; пополняет владелец или админ из кабинета:
    POST /v1/workspaces/{ws}/platform/purchases, по ключу нельзя. Цены открыты
    без ключа: `input_per_mtok_tiyn` и `output_per_mtok_tiyn` — за 1 млн токенов
    каждой модели. Пустой баланс — 402 с кодом `platform_balance_exhausted`.


    ### 4. Прикинуть цену вопроса


    Бесплатно: модель не отвечает, с баланса ничего не списывается.


    ```sh

    curl -X POST "$TUNGO_API/v1/companies/$CO/chat/count-tokens" -H "x-api-key:
    $TUNGO_KEY" -H "Content-Type: application/json" -d '{"message":"Какой НДС у
    последней реализации?"}'

    ```


    В ответе — `input_tokens`, `max_output_tokens`, `input_cost_tiyn` и
    `max_cost_tiyn` (это один вызов модели; ход может сделать их несколько,
    настоящая цена — по факту).


    ### 5. Задать первый вопрос


    ```sh

    curl -X POST "$TUNGO_API/v1/companies/$CO/chat" -H "x-api-key: $TUNGO_KEY"
    -H "Content-Type: application/json" -H "Idempotency-Key: first-question-1"
    -d '{"message":"Какой НДС у последней реализации?","stream":false}'

    ```


    В ответе — `answer`, `dialog_id` (пришлите его в следующем вопросе, чтобы
    продолжить разговор) и `usage` с токенами и ценой. Если `stream` не false,
    ответ приходит потоком событий. Компании нужно подключение к 1С: без него —
    409. Не оплачено подключение компании — 402 с кодом `onboarding_unpaid`.
    Потерялся ответ — повторите запрос с тем же `Idempotency-Key`: второго хода
    не будет.


    ### 6. Получать события и проверять подпись


    ```sh

    curl -X POST "$TUNGO_API/v1/workspaces/$WS/webhooks/endpoints" -H
    "x-api-key: $TUNGO_KEY" -H "Content-Type: application/json" -d
    '{"url":"https://example.kz/tungo-events","event_types":["proposal.written"]}'

    ```


    В ответе — `id` адреса и `secret` (whsec_…): по ключу прочитать его больше
    негде. Вебхуков нет в тарифе — 403 с кодом `webhooks_not_in_plan`. Пробное
    событие: POST /v1/workspaces/{ws}/webhooks/endpoints/{id}/test. Заголовки
    `webhook-id`, `webhook-timestamp` и `webhook-signature` проверяются так:


    ```js

    import { createHmac, timingSafeEqual } from 'node:crypto'


    // secret — whsec_…; headers — заголовки запроса; rawBody — тело строкой,
    как пришло, до разбора JSON.

    function verifyWebhook(secret, headers, rawBody, nowSec = Date.now() / 1000)
    {
      const id = headers['webhook-id']
      const ts = headers['webhook-timestamp']
      if (Math.abs(nowSec - Number(ts)) > 300) return false // старше 5 минут: повтор чужого запроса
      const key = Buffer.from(secret.slice('whsec_'.length), 'base64')
      const want = createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest()
      // В заголовке подписи через пробел: v1,<base64>. После смены секрета их две.
      return headers['webhook-signature'].split(' ').some((s) => {
        const got = Buffer.from(s.split(',')[1] ?? '', 'base64')
        return got.length === want.length && timingSafeEqual(got, want)
      })
    }

    ```


    Подпись не сошлась — отвечайте 400 и ничего не делайте. Одно событие может
    прийти дважды: отбрасывайте повторы по `id` тела.


    ---



    API для разработчиков: ключи, вебхуки, автоматизации, ИИ-бухгалтер компаний
    ключа. Вход — ключом API workspace (`x-api-key: tg_…` / `Authorization:
    Bearer tg_…`); управление самими ключами и вебхуками — ещё и сессией в
    браузере. Без того и другого — 401 с code missing_credentials.


    По ключу доступны (x-api-key-access у каждой операции): ручки ИИ-бухгалтера
    компаний ключа, чтение их карточек, автоматизации (automations.read /
    automations.manage), состояние подключения 1С (GET …/onec/status), вебхуки
    организации ключа (webhooks.manage, ключ на все компании), её баланс, расход
    и журнал платформы (GET /v1/workspaces/{ws}/platform/account, …/ledger,
    …/usage, …/audit), цены моделей (GET /v1/usage-rates), а также сам ключ о
    себе: GET /v1/api-key, GET /v1/api-key/usage, GET /v1/workspaces, GET
    /v1/companies.


    Id в адресах — публичные (ws_…, co_…, key_…). Публичные id организаций даёт
    GET /v1/workspaces.


    Деньги и лимиты: отказ из-за денег — 402 payment_required_error с error.code
    (platform_balance_exhausted, platform_cap_reached, platform_disabled,
    key_cap_reached, onboarding_unpaid): ждать бесполезно, нужно действие
    владельца организации. Вызовы по ключу идут мимо окон тарифа; лимит окна —
    только при входе сессией: 429 limit_error, code plan_limit_reached, с
    error.resets_at и Retry-After. Частота запросов по ключу — 429, code
    rate_limited, Retry-After; у каждого ответа по ключу — заголовки
    x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset (секунд до
    нового окна). Одновременных ходов ИИ на ключ — не больше настройки платформы
    (429 concurrent_turns_limit).


    Вызовы из браузера (CORS) не поддерживаются: ключ — секрет, держите его на
    сервере. Предварительный запрос OPTIONS к /v1 отвечает 403 с code
    cors_not_supported.


    Ошибки — одним видом:
    `{"type":"error","error":{"type":"…","message":"…"},"request_id":"…"}`;
    клиент ветвится по error.type.
servers:
  - url: https://api.tungo.kz
    description: Адрес API Tungo
security: []
paths:
  /v1/workspaces/{ws}/webhooks/endpoints:
    post:
      tags:
        - Вебхуки
      summary: Завести адрес
      description: >-
        Адрес — только https и не во внутренней сети (localhost, 10.x,
        192.168.x, 169.254.x… — и по DNS тоже); сервер доставки ещё раз
        проверяет это при каждой отправке. event_types — фильтр событий (null
        или нет — все). channels — id сценариев (scn_…): только их события,
        например итог сценария в CRM магазина. Сколько адресов можно — настройка
        платформы webhooks.max_endpoints_per_workspace (сверх — 429, code
        webhook_endpoints_limit). Одновременные заведения в одной организации
        идут по очереди; если другой адрес заводится дольше нескольких секунд —
        503 (code webhooks_unavailable), повторить позже. Секрет подписи — в
        ответе.


        Idempotency-Key: повтор с тем же ключом и тем же телом отдаёт прежний
        ответ (статус и тело) с заголовком Idempotent-Replayed: true и ничего не
        делает второй раз; тот же ключ с другим адресом или телом — 422
        (error.code = idempotency_key_reused); первый запрос с этим ключом ещё
        идёт — 409 (error.code = idempotency_in_progress). Запоминается только
        удачный ответ (2xx): после отказа повтор с тем же ключом выполнится
        заново. Ключ живёт сутки (настройка idempotency.keys), область —
        организация и тот, кто прислал (ключ API или человек).


        Доступ: Владелец или админ workspace; ключ API — с правом
        webhooks.manage.


        Доступно по ключу API.
      operationId: createWorkspaceWebhooksEndpoint
      parameters:
        - schema:
            type: string
            description: id организации (workspace), ws_… — из GET /v1/workspaces
          required: true
          description: id организации (workspace), ws_… — из GET /v1/workspaces
          name: ws
          in: path
        - schema:
            type: string
            maxLength: 255
            description: >-
              Ключ повтора (например, UUID): повтор с тем же ключом и тем же
              телом не выполняет действие второй раз, а отдаёт прежний ответ
          required: false
          description: >-
            Ключ повтора (например, UUID): повтор с тем же ключом и тем же телом
            не выполняет действие второй раз, а отдаёт прежний ответ
          name: Idempotency-Key
          in: header
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEndpointCreate'
      responses:
        '201':
          description: Адрес заведён
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointCreated'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
            Idempotent-Replayed:
              description: >-
                true — это сохранённый ответ на повтор с тем же Idempotency-Key:
                действие второй раз не выполнялось. Нет заголовка — запрос
                выполнен сейчас
              schema:
                type: string
                enum:
                  - 'true'
        '400':
          description: >-
            Запрос неверен — показать error.message у формы; при error.code =
            validation_failed — ошибки полей в error.fields (error.type:
            invalid_request_error)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
        '401':
          description: >-
            Нет входа (сессия закончилась или ключ API неверен) — отправить на
            вход (error.type: authentication_error)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
        '403':
          description: >-
            Нельзя: нет права или роли, организация заблокирована, вход не тем
            способом — показать error.message (error.type: permission_error)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
        '404':
          description: 'Не найдено (или чужое) (error.type: not_found_error)'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
        '409':
          description: >-
            Состояние не позволяет — перечитать объект и показать error.message
            (error.type: conflict_error)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
        '413':
          description: >-
            Тело запроса больше предела этого адреса (error.code =
            payload_too_large)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
        '422':
          description: >-
            Idempotency-Key уже использован для другого запроса (error.code =
            idempotency_key_reused)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
        '429':
          description: >-
            Предел (частота, окно тарифа, число объектов) — см. Retry-After и
            error.resets_at (error.type: limit_error)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
            Retry-After:
              description: >-
                Через сколько секунд повторить запрос (отказ пройдёт сам); нет —
                ждать бесполезно, смотреть error.code
              schema:
                type: integer
                minimum: 1
        '503':
          description: >-
            Временно недоступно — повторить позже (error.type:
            unavailable_error)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            x-request-id:
              description: >-
                Номер запроса (тот же, что request_id в теле ошибки) — назвать в
                обращении в поддержку. Его всегда создаёт сервер: присланный
                клиентом x-request-id номером не становится
              schema:
                type: string
                example: req_3f2a9c0d1e4b4c5d8e7f6a5b4c3d2e1f
            x-ratelimit-limit:
              description: >-
                Только при входе по ключу API: сколько запросов можно в текущем
                окне — самый тесный предел из ключа и организации
              schema:
                type: integer
            x-ratelimit-remaining:
              description: >-
                Только при входе по ключу API: сколько запросов осталось по
                этому пределу в текущем окне
              schema:
                type: integer
            x-ratelimit-reset:
              description: >-
                Только при входе по ключу API: секунд до нового окна этого
                предела
              schema:
                type: integer
      security:
        - session: []
        - apiKey: []
        - bearerKey: []
components:
  schemas:
    WebhookEndpointCreate:
      type: object
      properties:
        url:
          type: string
          minLength: 1
          maxLength: 2000
          description: >-
            Адрес приёмника: только https и не во внутренней сети (localhost,
            10.x, 192.168.x… — проверяется и по DNS), до 2000 знаков
          example: https://example.com/tungo/webhooks
        description:
          type: string
          maxLength: 500
          description: Подпись адреса для людей (до 500 знаков)
          example: Учётная система
        event_types:
          type:
            - array
            - 'null'
          items:
            type: string
            minLength: 1
            maxLength: 100
          maxItems: 50
          description: >-
            Какие события слать на адрес — имена из GET …/webhooks/event-types
            (до 50). null или не передано при заведении — все события
          example:
            - proposal.written
            - payment.succeeded
        channels:
          type:
            - array
            - 'null'
          items:
            type: string
            pattern: ^scn_[0-9a-z]{26}$
          maxItems: 10
          description: >-
            Каналы — id сценариев автоматизаций (scn_…, до 10). Заданы — на
            адрес приходят только события этих сценариев
            (automation.run.completed, automation.run.failed,
            automation.run.notice, automation.write_unknown), и никаких других:
            так итог конкретного сценария идёт в свою систему. null или не
            передано при заведении — все события (по event_types)
          example:
            - scn_01jz8x3m4n5p6q7r8s9t0v1w2x
        enabled:
          type: boolean
          description: >-
            false — не слать на адрес, пока не включат снова. При заведении по
            умолчанию — включён
      required:
        - url
      description: Новый адрес вебхуков.
    WebhookEndpointCreated:
      allOf:
        - $ref: '#/components/schemas/WebhookEndpoint'
        - type: object
          properties:
            secret:
              type:
                - string
                - 'null'
              description: >-
                Секрет подписи whsec_…: по ключу API его больше негде прочитать,
                только сменить (POST …/secret/rotate). Хранить как пароль. null
                — повтор с тем же Idempotency-Key (секрет не запоминается) или
                Svix не отдал его сразу
              example: whsec_…
            secret_note:
              type: string
              description: 'Только в повторе с тем же Idempotency-Key: где взять секрет'
          required:
            - secret
      description: Заведённый адрес вебхуков и его секрет подписи.
    Error:
      type: object
      properties:
        type:
          type: string
          enum:
            - error
          description: 'Всегда «error»: так тело ошибки отличается от обычного ответа.'
        error:
          $ref: '#/components/schemas/ErrorDetail'
        request_id:
          type:
            - string
            - 'null'
          description: >-
            Номер запроса (тот же, что в заголовке x-request-id). Показывать
            мелко рядом с ошибкой с кнопкой «скопировать»: по нему поддержка
            находит запрос в журнале. null — номер не успел появиться (очень
            ранний отказ).
          example: req_4f9c2a7e1b3d4c5a8e6f7a9b0c1d2e3f
      required:
        - type
        - error
        - request_id
      description: >-
        Тело любой ошибки API (статусы 4xx и 5xx):
        `{"type":"error","error":{"type":"…","code":"…","message":"…"},"request_id":"…"}`.
        Интерфейс ветвится по error.type и error.code, человеку показывает
        error.message и request_id.
    WebhookEndpoint:
      type: object
      properties:
        id:
          type: string
          description: id адреса (ep_…) — для адресов …/webhooks/endpoints/{id}
          example: ep_2xyzExample
        url:
          type: string
          description: Куда слать события (https)
          example: https://example.com/tungo/webhooks
        description:
          type: string
          description: Подпись адреса для людей; пустая строка — не задана
        event_types:
          type:
            - array
            - 'null'
          items:
            type: string
          description: Какие события слать (имена из …/webhooks/event-types); null — все
        channels:
          type:
            - array
            - 'null'
          items:
            type: string
          description: >-
            Каналы — id сценариев автоматизаций (scn_…): на адрес идут только
            события этих сценариев; null — все события
        enabled:
          type: boolean
          description: >-
            false — на адрес сейчас не шлётся ничего, пока не включат снова
            (PATCH enabled: true)
        created_at:
          type: string
          format: date-time
          example: '2026-10-05T09:30:00.000Z'
          description: Когда заведён, ISO 8601 UTC
        updated_at:
          type: string
          format: date-time
          example: '2026-10-05T09:30:00.000Z'
          description: Когда менялся последний раз, ISO 8601 UTC
      required:
        - id
        - url
        - description
        - event_types
        - channels
        - enabled
        - created_at
        - updated_at
      description: 'Адрес вебхуков: сервер клиента, куда Tungo шлёт события организации.'
    ErrorDetail:
      type: object
      properties:
        type:
          type: string
          enum:
            - invalid_request_error
            - authentication_error
            - payment_required_error
            - permission_error
            - not_found_error
            - conflict_error
            - gone_error
            - limit_error
            - api_error
            - unavailable_error
          description: >-
            Вид ошибки — по нему ветвится клиент (не по тексту message). Статус
            HTTP у вида один, кроме invalid_request_error:

            - `invalid_request_error` (400) — запрос неверен: поле не прошло
            проверку, неверный формат, действие сейчас недопустимо. Показать
            message рядом с формой; повтор без исправления не поможет. Обычно
            400; 413 и 422 — у кодов, где это сказано в списке code.

            - `authentication_error` (401) — нет входа: сессия закончилась,
            cookie нет, ключ API неверен, отозван или истёк. Кабинет — отправить
            на страницу входа; по ключу — проверить ключ (см. code).

            - `payment_required_error` (402) — нужны деньги или решение
            владельца/админа организации: ждать бесполезно. Показать message и
            кнопку действия по code (оформить тариф, пополнить баланс, поднять
            потолок); без code — не оплачено подключение компании.

            - `permission_error` (403) — нельзя: не хватает права или роли,
            организация заблокирована, вход не тем способом. Показать message (в
            нём сказано, к кому обратиться); детали — в code и полях рядом.

            - `not_found_error` (404) — нет такого объекта — или он чужой: чужие
            организации, компании и записи тоже отвечают 404, чтобы не
            раскрывать, что они есть. Показать «не найдено» и вернуть к списку.

            - `conflict_error` (409) — состояние не позволяет: уже сделано, уже
            идёт другое действие, версия устарела. Перечитать объект, обновить
            экран и показать message.

            - `gone_error` (410) — объекта больше нет: разговор не найден или
            истёк (вопрос в чате, ответ на вопрос ИИ, подсчёт токенов — начать
            новый разговор), ход потерян при перезапуске сервера, ссылка
            привязки программы устарела или уже использована (code
            connector_link_gone). Повторять незачем.

            - `limit_error` (429) — предел: частота запросов, окно тарифа, число
            объектов или мест. Если есть заголовок Retry-After или resets_at —
            пройдёт само, показать, когда; иначе нужно освободить место (удалить
            лишнее) или сменить тариф.

            - `api_error` (500) — сбой на нашей стороне. Показать message и
            request_id (для поддержки); повторить позже.

            - `unavailable_error` (503) — временно недоступно (внешний сервис,
            ИИ, настройка сервера). Повторить позже; если повторяется — сообщить
            request_id в поддержку.
          example: payment_required_error
        message:
          type: string
          description: >-
            Готовый текст для человека по-русски: что случилось, что делать и к
            кому обратиться. Показывать как есть; не разбирать — формулировки
            меняются.
          example: >-
            Баланс доп. использования закончился — пополнить его или включить
            автопополнение могут владелец и админ workspace.
        code:
          type: string
          description: >-
            Уточнение вида: по нему выбирается действие интерфейса (кнопка
            «Пополнить», «Войти иначе»…). Нет поля — хватает type и message.
            Известные коды:

            - `sso_domain_taken` (409) — домен SSO уже подтверждён другой
            организацией

            - `sso_last_verified_domain` (409) — включён обязательный вход, а
            это последний подтверждённый домен — сначала выключить обязательный
            вход

            - `sso_login_required` (400) — включить обязательный вход можно
            только из сессии, открытой через SSO этой организации

            - `domain_verification_failed` (400) — запись DNS для домена не
            найдена или не совпала — проверить и повторить

            - `oidc_openid_scope_required` (400) — в scopes сервера входа OIDC
            нет openid — добавить её: без неё вход через SSO не пройдёт

            - `enterprise_only` (403) — возможность есть только на тарифе
            Enterprise

            - `groups_limit` (429) — достигнут предел групп в организации

            - `custom_roles_limit` (429) — достигнут предел своих ролей в
            организации

            - `group_managed_by_directory` (409) — группа из каталога: название
            и состав меняются только там

            - `group_member_not_in_workspace` (400) — в группу можно добавить
            только сотрудника этой организации

            - `role_above_ceiling` (400) — роль даёт права выше потолка
            организации

            - `unknown_model` (400) — такой модели нет — список в
            available_models

            - `price_required` (400) — админка, тариф целиком: у платного тарифа
            нужна цена (price)

            - `lago_rejected` (409) — админка, тариф целиком: Lago отказал по
            существу (4xx, текст Lago в message) — правила не изменены, повтор
            без правки не поможет

            - `price_mismatch` (400) — админка, тариф целиком: цена не сходится
            с правилами (место без per_seat, per_seat без цены места, цена у
            бесплатного)

            - `model_not_allowed` (403) — политика организации не разрешает эту
            модель, а подходящей разрешённой нет — админу дополнить список

            - `retention_too_short` (400) — срок хранения меньше наименьшего

            - `audit_export_range` (400) — неверный период выгрузки журнала:
            конец раньше начала или период слишком длинный

            - `compliance_disabled` (403) — адрес для проверок выключен —
            владелец включает его в настройке

            - `missing_credentials` (401) — нет ни cookie сессии, ни ключа API —
            войти или передать x-api-key

            - `link_revoked` (401) — вход в Tungo из 1С больше не действует
            (вышли, отключили на сайте, вошли в той же базе заново, компания или
            человек заблокированы) — 1С просит войти заново

            - `login_denied` (403) — вход из 1С отклонён на сайте Tungo — 1С
            показывает отказ

            - `code_expired` (410) — код входа из 1С устарел или уже использован
            — 1С просит новый код

            - `code_gone` (410) — код входа из 1С уже подтверждён, отклонён или
            устарел — на сайте подтверждать нечего

            - `invalid_api_key` (401) — ключ API неверен (опечатка или удалён)

            - `key_revoked` (401) — ключ API отозван (при правке ключа — 409 с
            тем же code: отозванный ключ не меняется)

            - `key_expired` (401) — срок ключа API истёк — сменить секрет (POST
            …/api-keys/{id}/roll: срок начнётся заново) или выпустить новый (при
            правке срока — 409 с тем же code: PATCH истёкший ключ не оживляет)

            - `key_disabled` (401) — ключ API выключен — включить может автор
            ключа или владелец организации (POST …/api-keys/{id}/enable)

            - `key_creator_lost_access` (401) — тот, кто выпустил ключ, больше
            не владелец/админ организации — ключ недействителен

            - `user_banned` (401) — вход в аккаунт закрыт администратором Tungo
            — только поддержка Tungo

            - `onboarding_unpaid` (402) — подключение компании к ИИ-бухгалтеру
            не оплачено (разовый платёж): владельцу/админу организации —
            «Оплатить» в настройках компании; остальным — сообщить им

            - `onboarding_pending` (402) — оплата подключения компании ещё
            проходит в банке — ИИ заработает после подтверждения; опрашивать
            состояние подключения

            - `no_active_plan` (402) — нет действующей подписки (не оформлена,
            закончилась, первая оплата не прошла или ждёт 3-D Secure).
            Владельцу/админу — кнопка в настройки оплаты; остальным —
            «обратитесь к владельцу организации». Что именно случилось — в
            message

            - `balance_exhausted` (402) — баланс доп. использования кончился.
            Владельцу/админу — «Пополнить баланс» или включить автопополнение;
            остальным — сообщить им

            - `workspace_cap_reached` (402) — достигнут месячный потолок доп.
            использования организации. resets_at — 1-е число следующего месяца,
            00:00 по Алматы; раньше — если админ поднимет потолок

            - `report_busy` (429) — сейчас собирается много отчётов команды:
            повторить через время из Retry-After

            - `report_timeout` (503) — отчёт команды не успел собраться:
            сократить период или выбрать разбивку по месяцам

            - `company_cap_reached` (402) — достигнут месячный потолок доп.
            использования компании. Письмо владельцу и админам уже отправлено.
            resets_at — 1-е число; раньше — если админ поднимет потолок (PUT
            /v1/workspaces/{ws}/team/company-caps/{co})

            - `member_cap_reached` (402) — достигнут личный месячный потолок
            доп. использования сотрудника. resets_at — 1-е число; раньше — если
            админ поднимет его потолок

            - `key_cap_reached` (402) — достигнут месячный потолок расхода ключа
            API (или остаток меньше оценки одного вызова). resets_at — 1-е число

            - `platform_balance_exhausted` (402) — баланс платформы пуст: вызов
            по ключу или автоматизация не сделаны. Пополнить — POST
            /v1/workspaces/{ws}/platform/purchases или автопополнением

            - `platform_cap_reached` (402) — достигнут месячный потолок трат
            платформы. resets_at — 1-е число следующего месяца, 00:00 по Алматы;
            раньше — поднять потолок в PUT /v1/workspaces/{ws}/platform/account

            - `platform_disabled` (402) — платформа выключена в организации:
            вызовы по ключам и автоматизации остановлены. Включить — PUT
            /v1/workspaces/{ws}/platform/account

            - `free_plan_chat_only` (402) — бесплатный тариф: пачки из кабинета
            только на платных тарифах. Ключам API и автоматизациям тариф не
            нужен

            - `free_limit_unavailable` (402) — бесплатный лимит этой учётной
            записи не положен (проверка регистрации или решение администратора)
            — оформить тариф

            - `plan_company_limit` (402) — в организации уже столько компаний не
            в архиве, сколько разрешает тариф (max_companies в GET /v1/plans;
            limit и plan_code — в ответе): новую не завести и из архива не
            вернуть. Убрать лишнюю в архив или перейти на тариф больше

            - `effort_not_in_plan` (402) — поле effort в чате на тарифе без
            выбора усилия (max_effort тарифа null, например бесплатный): ход не
            начат. Прислать вопрос без effort или оформить платный тариф

            - `model_not_in_plan` (402) — модель сильнее потолка тарифа
            (plans.model_ceiling): вызов не сделан; более сильные модели — на
            платных тарифах

            - `missing_permission` (403) — не хватает права в компании (или у
            ключа API); какого — в поле permission

            - `login_method_not_allowed` (403) — организация пускает к своим
            данным только после входа другим способом; какими — в
            allowed_methods. Предложить выйти и войти так

            - `ip_not_allowed` (403) — ключ API не принимает запросы с этого
            адреса — поправить allowed_ips ключа (PATCH …/api-keys/{id}) или
            вызывать с разрешённого адреса

            - `key_write_limit` (403) — запись в 1С по ключу API — сверх его
            пределов (сумма на документ или в день, виды документов) или правило
            автоодобрения шире пределов ключа; в сообщении — что и на сколько

            - `human_only` (403) — это решение принимает только человек в
            кабинете Tungo, не ключ API: например, отклонить «не знаем, записан
            ли» на снимке базы без проверки 1С (confirm_unknown_write)

            - `autonomy_raise_requires_session` (403) — поднять уровень доверия
            ИИ или потолки компании можно только владельцу или админу
            организации из кабинета; ключом API — только понизить

            - `id_path_required` (400) — для автоодобрения по хуку задайте хуку
            id_path — путь к номеру операции в теле события: без него повтор
            доставки нельзя отличить от новой операции

            - `directbank_rule_exists` (400) — у компании уже есть сценарий с
            правилом для выписки DirectBank — правило выписки одно на компанию

            - `event_not_found` (404) — события нет в этой компании или оно
            удалено по сроку хранения — для пробного прогона выберите событие
            посвежее

            - `event_body_unavailable` (409) — тело события зашифровано, а ключ
            шифрования на сервере сменился — прогнать сценарий на нём нельзя

            - `scenario_steps_required` (409) — у сценария цепочка шагов, а в
            замене (PUT) нет ни steps, ни output: передайте steps явно, иначе
            замена молча убрала бы цепочку

            - `scenario_output_required` (409) — у сценария форма итога, а в
            замене (PUT) нет ни steps, ни output: передайте output явно (null —
            снять форму)

            - `automation_queue_full` (429) — у компании слишком много запусков
            в очереди: повторите позже (событие хука отправитель повторит сам)

            - `restarting` (503) — сервис перезапускается: новый ход не начат —
            повторите через Retry-After

            - `company_suspended` (403) — работа с компанией приостановлена
            (решение платформы или оплаты); карточка видна, работать, править и
            архивировать нельзя (архив — 409 с тем же code)

            - `company_archived` (403) — компания в архиве: карточка видна,
            работать с ней нельзя. Вернуть — POST
            /v1/companies/{company_id}/unarchive (владелец компании или
            владелец/админ организации)

            - `workspace_blocked` (403) — организация заблокирована
            администратором платформы — только поддержка Tungo

            - `untrusted_origin` (403) — запрос пришёл не со страницы Tungo
            (защита от подделки запросов) — открыть кабинет по обычному адресу;
            для /admin/* — только со страниц ADMIN_ORIGINS

            - `cors_not_supported` (403) — вызов API из чужого браузерного кода
            (CORS) не поддерживается: ключ API — секрет сервера

            - `api_keys_disabled_by_policy` (403) — политика организации
            запрещает ключи API

            - `owner_role_reserved` (403) — владельца компании назначает, меняет
            и снимает только владелец или админ организации

            - `role_above_yours` (403) — у выдаваемой (или снимаемой) роли есть
            права, которых нет у вас; роль — в поле role, лишние права — в
            permissions

            - `not_key_creator` (403) — менять компании, права, срок и секрет
            ключа, снимать и поднимать его пределы записи в 1С может только тот,
            кто его выпустил (ужесточить пределы может любой админ)

            - `transfer_wider_than_target` (403) — передать ключ нельзя: у
            нового владельца нет нужного права (или доступа) в одной из компаний
            ключа

            - `invalid_allowed_ips` (400) — в allowed_ips ключа — не IP-адрес и
            не подсеть CIDR; какая запись — в сообщении

            - `transfer_target_not_admin` (400) — передать ключ можно только
            владельцу или админу этой организации

            - `platform_model_not_allowed` (403) — модель сильнее потолка
            платформы (настройка platform.billing): вызов не сделан и ничего не
            списано

            - `managed_by_sso` (403) — удаление аккаунта: аккаунт ведёт
            организация (SSO или SCIM) — удаляет её администратор; организации —
            в workspaces

            - `fresh_session_required` (403) — удаление аккаунта без почты
            (Telegram): нужен свежий вход — выйти, войти снова и подтвердить

            - `api_key_not_allowed` (403) — действие только из кабинета
            (сессия), не по ключу API: удаление аккаунта

            - `not_own_key` (403) — по ключу API виден только расход самого
            этого ключа

            - `webhooks_not_in_plan` (403) — вебхуков нет в тарифе организации

            - `admin_2fa_required` (403) — админ-API: у администратора платформы
            нет второго фактора или эта сессия не подтверждена кодом
            приложения-аутентификатора (POST /v1/auth/two-factor/enable, затем
            verify-totp)

            - `two_factor_required` (403) — отключить второй фактор, показать
            его секрет или выпустить резервные коды — только после кода из
            приложения-аутентификатора в этой сессии

            - `webhooks_require_all_companies` (403) — вебхуки — только ключу на
            все компании организации (при выпуске ключа — 400 с тем же code)

            - `audit_requires_all_companies` (403) — журнал организации — только
            ключу на все компании организации

            - `policy_blocked` (403) — одобрение: организация не доверяет ИИ
            записывать такой документ этим способом (поле level — уровень
            доверия); одобрить по одному или поднять уровень

            - `onec_read_only` (403) — одобрение: у пользователя 1С из
            подключения нет права записи — дать права в 1С

            - `validation_failed` (400) — тело или параметры запроса не прошли
            проверку: что не так с каждым полем — в fields (путь, код, текст
            по-русски). Подсветить поля формы; общий message — над формой

            - `invalid_json` (400) — тело запроса — не JSON-объект

            - `personal_workspace` (400) — в личной организации нет сотрудников,
            приглашений и политик — нужна организация Team или Enterprise

            - `api_key_required` (400) — адрес только для запроса по ключу API

            - `email_code_unavailable` (400) — удаление аккаунта: у аккаунта нет
            почты для кода (вход через Telegram) — подтверждать свежим входом,
            без кода

            - `deletion_code_invalid` (400) — удаление аккаунта: неверный код из
            письма; сколько попыток осталось — attempts_left

            - `deletion_code_expired` (400) — удаление аккаунта: код истёк,
            попытки кончились или код не запрашивался — запросить новый (POST
            /v1/me/deletion/code)

            - `unsafe_url` (400) — адрес вебхука недопустим (внутренняя сеть, не
            HTTPS)

            - `idempotency_key_invalid` (400) — Idempotency-Key неверного вида

            - `payload_too_large` (413) — тело запроса (или события хука) больше
            допустимого; пределы — настройки платформы

            - `idempotency_key_reused` (422) — этот Idempotency-Key уже был у
            другого запроса — для нового действия нужен новый ключ

            - `has_blockers` (422) — одобрение: у предложения есть блокеры —
            сначала исправить их

            - `batch_too_large` (413) — одобрение пачкой: предложений больше
            предела (поля limit, requested) — разбить на части

            - `unknown_kind` (400) — настройки писем: такого вида уведомлений
            нет — взять список из GET /v1/me/notifications

            - `kind_locked` (400) — настройки писем: этот вид (безопасность и
            аккаунт) выключить нельзя — переключатель неактивен (locked)

            - `onec_rejected` (400) — одобрение: 1С отклонила документ (причина
            — в message): исправить в 1С или построить предложение заново

            - `proposal_not_found` (404) — предложения с таким id нет в компании

            - `export_link_expired` (404) — ссылка на архив выгрузки истекла или
            неверна — получить новую: GET /v1/me/export

            - `batch_not_found` (404) — одобрение пачкой: задания с таким
            batch_id нет (или в нём нет предложений)

            - `idempotency_in_progress` (409) — первый запрос с этим
            Idempotency-Key ещё выполняется — подождать и повторить, придёт тот
            же ответ

            - `idempotency_response_not_kept` (409) — запрос с этим
            Idempotency-Key уже выполнен, но копия ответа не хранится (в нём
            персональные данные): результат — по ссылке в ответе (dialog_url)
            или в списке; статус первого ответа — original_status

            - `idempotency_response_too_large` (409) — запрос с этим
            Idempotency-Key уже выполнен, но ответ слишком большой, чтобы
            повторить его целиком: результат — в списке; статус первого ответа —
            original_status

            - `sole_owner` (409) — удаление аккаунта: вы единственный владелец
            организации с другими участниками (workspaces) — передать владение
            (POST /v1/workspaces/{ws}/ownership) или удалить организацию

            - `account_deletion_in_progress` (409) — удаление аккаунта: фон уже
            стирает аккаунт — новый код и подтверждение не принимаются, отменить
            нельзя

            - `wrong_status` (409) — предложение уже не в том состоянии (поле
            status — нынешнее): обновить его

            - `wrong_state` (409) — запуск автоматизации уже не в том состоянии
            (поле state — нынешнее)

            - `dialog_closed` (409) — разговор закрыт (поле reason — почему):
            начать новый

            - `dialog_id_taken` (409) — разговор с таким dialog_id уже есть —
            для нового прислать другой id или не присылать его

            - `turn_in_progress` (409) — в разговоре уже идёт ход ИИ (поле turn
            — его номер): дождаться его конца или остановить

            - `turn_superseded` (409) — читаемый ход уже закончился и идёт
            следующий (поле turn) — читать его с начала

            - `dialog_changed` (409) — разговор только что изменился в другом
            окне или на другом сервере Tungo — открыть его заново (GET
            …/chat/{id}) и повторить

            - `already_answered` (409) — на этот вопрос ИИ уже ответили (поле
            turn — ход с ответом)

            - `question_stale` (409) — вопрос ИИ устарел (в разговоре уже другой
            вопрос или его нет) — обновить разговор

            - `dismissed` (409) — вопрос ИИ закрыт без ответа — написать обычное
            сообщение

            - `job_running` (409) — задание (пачка) ещё идёт — дождаться отчёта;
            поле batch_id

            - `payload_changed` (409) — одобрение: документ изменился после
            превью — построить предложение заново

            - `onec_conflict` (409) — одобрение: 1С отказала из-за конфликта
            (объект занят или изменён) — повторить позже

            - `onec_not_found` (409) — одобрение: в 1С нет объекта, на который
            ссылается документ — построить предложение заново

            - `plan_limit_reached` (429) — лимит окна тарифа исчерпан; resets_at
            и Retry-After — когда обновится. Показать время; если в message
            предложено доп. использование — дать кнопку включить

            - `rate_limited` (429) — слишком часто (по ключу API, уведомления
            ePay с одного адреса, попытки кода второго фактора) — подождать
            Retry-After секунд

            - `concurrent_turns_limit` (429) — по ключу API уже идёт предельное
            число ходов ИИ одновременно — дождаться окончания

            - `api_keys_limit` (429) — в организации предельное число
            действующих ключей API — отозвать ненужные

            - `webhook_endpoints_limit` (429) — предельное число адресов
            вебхуков — удалить ненужные

            - `export_too_soon` (429) — выгрузку данных можно запрашивать не
            чаще раза в сутки: next_request_at и Retry-After — когда можно снова

            - `hook_rate_limited` (429) — приём событий хука: больше
            automations.hook_events_per_minute в минуту — повторить через
            Retry-After секунд

            - `lago_unavailable` (503) — админка, тариф целиком: Lago не
            настроен или не ответил (сеть, 5xx) — правила не изменены, повторить
            позже

            - `model_price_missing` (503) — у модели ИИ не задана цена — сбой
            настройки платформы, ничего не списано; повторить позже

            - `data_export_disabled` (503) — выгрузка данных на сервере не
            настроена (поддержка Tungo)

            - `webhooks_disabled` (503) — вебхуки на сервере не настроены

            - `webhooks_unavailable` (503) — служба доставки вебхуков временно
            недоступна

            - `model_not_configured` (503) — сервис модели ИИ не настроен на
            сервере — повторить позже (Retry-After)

            - `write_unknown` (503) — одобрение: исход записи в 1С неизвестен
            (связь оборвалась) — проверить документ в 1С по метке (поле marker);
            повтор безопасен (retry_safe); слишком ранний повтор в 1С не пишет —
            подождать retry_after секунд (Retry-After)

            - `onec_unavailable` (503) — 1С сейчас не отвечает — повторить позже
            (Retry-After)

            - `onec_check_busy` (503) — проверка связи 1С: сервер сейчас
            проверяет слишком много подключений — повторить через Retry-After
            секунд

            - `onec_failed` (503) — записать документ в 1С не удалось по
            неизвестной причине — повторить позже

            - `journal_unavailable` (503) — журнал решений недоступен — пачка не
            одобрена, повторить позже

            - `hook_secret_unavailable` (503) — приём событий хука: секрет
            подписи сейчас не открыть — отправителю повторить доставку позже

            - `secret_box_missing` (503) — на сервере не задан ключ шифрования
            настроек — секрет подписи хука сохранить нельзя (поддержка Tungo)

            - `not_personal` (409) — перевод в команду: организация уже не
            личная — обновить экран

            - `subscription_blocks_conversion` (409) — перевод в команду:
            действует подписка для одного человека — сначала отменить её и
            дождаться конца периода

            - `subscription_kind_mismatch` (409) — админка: действующая подписка
            оформлена на другой вид организации — вид не меняется, пока она идёт

            - `enterprise_features_active` (409) — админка: у организации
            подключены SSO или SCIM — сначала отключить, потом снимать
            Enterprise

            - `too_many_members_for_personal` (409) — админка: в личной
            организации один человек — сначала убрать остальных участников

            - `open_debt` (409) — есть неоплаченный счёт — сначала оплатить; в
            плане удаления этот же код лежит в blockers

            - `active_work` (409) — в организации идут ходы ИИ или автоматизации
            — дождаться окончания и повторить; в плане удаления этот же код
            лежит в blockers

            - `deletion_already_scheduled` (409) — удаление организации уже
            запланировано — показать дату из плана

            - `deletion_purging` (409) — очистка организации уже идёт — отменить
            её нельзя

            - `workspace_deleting` (409) — админка: организация удаляется по
            просьбе владельца — блок удаления снимает только отмена удаления

            - `invitation_not_pending` (409) — приглашение принято, отозвано или
            истекло — письмо не отправить, пригласить заново

            - `last_owner` (409) — это последний владелец организации — сначала
            передать владение другому участнику

            - `seats_by_contract` (409) — места Enterprise — по договору, карта
            и докупка не работают: обратиться к менеджеру

            - `no_subscription` (409) — нет действующей подписки — сначала
            оформить тариф

            - `not_per_seat` (409) — этот тариф не считает оплату за место —
            докупка не нужна, предел мест показан в ответе GET …/seats

            - `subscription_ended` (409) — возобновление: период отменённой
            подписки уже закончился — ничего не списано, оформить тариф заново
            (повторный PUT — обычное оформление)

            - `subscription_busy` (409) — подписка уже меняется другим запросом
            (отмена или возобновление) — обновить экран через несколько секунд

            - `subscription_ending` (409) — подписка отменена и закончится в
            конце периода — места не докупаются и не сокращаются

            - `seats_unpaid_debt` (409) — подписка просрочена — сначала оплатить
            счёт; участники остаются, новых приглашать нельзя

            - `idempotency_conflict` (409) — докупка: этот ключ уже использован
            с другим числом мест — для новой покупки нужен новый ключ

            - `seat_quote_changed` (409) — докупка: сумма изменилась (другой
            день или новая цена), деньги не списаны — показать новую сумму из
            поля и спросить снова

            - `no_paid_seats` (409) — оплаченных мест ещё нет — сокращать нечего

            - `seats_below_occupied` (409) — занято больше мест, чем просите
            оставить — сначала убрать участников или отозвать приглашения

            - `not_enterprise` (409) — админка: места по договору есть только у
            Enterprise — сначала поставить вид

            - `per_seat_plan_change` (409) — смена тарифа с оплатой за место не
            делается сразу: Lago взял бы плату за места дважды. Отменить и
            оформить новый с конца периода

            - `confirm_name_mismatch` (400) — удаление организации: название
            введено неверно — ввести точно как в плане удаления

            - `below_min_seats` (400) — на этом тарифе мест меньше нельзя:
            минимум — min_seats тарифа

            - `seats_over_max` (400) — мест больше предела одной организации
            (team.limits.max_seats) — обратиться в поддержку

            - `seats_above_paid` (400) — PUT …/seats только сокращает; новые
            места — через POST …/seats с оплатой

            - `onec_check_running` (429) — проверка связи 1С уже идёт у этой
            компании, у вас (другая компания) или у двух других компаний
            организации — дождаться её итога и повторить (Retry-After)

            - `invitation_resend_too_soon` (429) — письмо с приглашением уже
            отправлено только что — подождать Retry-After секунд

            - `seats_exhausted` (429) — свободные места закончились: докупите
            места или освободите их, отозвав приглашение

            - `seat_price_unknown` (503) — цена места сейчас неизвестна (тариф
            не прочитан или настроен неверно), деньги не списаны — повторить
            позже

            - `otp_mail_failed` (503) — письмо с кодом входа не отправлено:
            попробуйте позже

            - `seat_period_unknown` (503) — не удалось сверить период подписки с
            биллингом: деньги не списаны, попробуйте позже


            Незнакомый code — вести себя по type.
          example: balance_exhausted
        permission:
          type: string
          description: >-
            При code = missing_permission — какого права не хватает: права в
            компании (company.read, company.manage, company.members.manage,
            onec.connect, proposals.create, proposals.approve, chat.use,
            audit.read, automations.manage) или права только ключа API
            (automations.read, webhooks.manage). Показать «нужно право …» и
            предложить попросить админа (или выпустить ключ с этим правом).
          example: proposals.approve
        resets_at:
          type: string
          format: date-time
          description: >-
            Когда ограничение снимется само — ISO 8601, UTC. Есть у
            plan_limit_reached (конец окна тарифа) и у месячных потолков
            (workspace_cap_reached, company_cap_reached, member_cap_reached,
            key_cap_reached, platform_cap_reached — 1-е число, 00:00 по Алматы).
            Показать в местном времени: «Лимит обновится в 14:30». Нет поля —
            само не пройдёт.
          example: '2026-11-01T19:00:00.000Z'
        allowed_methods:
          type: array
          items:
            type: string
            enum:
              - email_otp
              - google
              - apple
              - telegram
              - sso
          description: >-
            При code = login_method_not_allowed — какими способами входа
            организация пускает к своим данным: email_otp — код из почты,
            google, apple, telegram, sso — SSO организации. Предложить выйти и
            войти одним из них.
        role:
          type: string
          description: >-
            При code = role_above_yours — ключ роли в компании, которую нельзя
            выдать или снять (например chief_accountant).
        permissions:
          type: array
          items:
            type: string
          description: >-
            При code = role_above_yours — права этой роли, которых нет у того,
            кто выдаёт. Показать списком: «у роли есть права, которых нет у вас:
            …».
        fields:
          type: array
          items:
            $ref: '#/components/schemas/FieldError'
          description: >-
            При code = validation_failed — ошибки по полям, в порядке проверки;
            у одного поля может быть несколько.
      required:
        - type
        - message
      additionalProperties: {}
      description: >-
        Что пошло не так. Все 503 — с заголовком Retry-After (через сколько
        секунд повторить). Кроме описанных, у отдельных ручек бывают свои поля
        рядом с code (например status у wrong_status, state у wrong_state,
        reason у dialog_closed) — они описаны у этих ручек.
    FieldError:
      type: object
      properties:
        path:
          type: string
          description: >-
            Путь к полю через точку, как в теле запроса или имени параметра:
            `name`, `lines.0.amount`. Пустая строка — всё тело (не объект,
            лишние поля).
          example: bin
        code:
          type: string
          enum:
            - invalid_type
            - too_small
            - too_big
            - invalid_format
            - invalid_value
            - not_multiple_of
            - unrecognized_keys
            - invalid_union
            - invalid_key
            - invalid_element
            - custom
          description: >-
            Что не так: invalid_type — не тот тип или поле не передано;
            too_small / too_big — короче/меньше или длиннее/больше допустимого;
            invalid_format — неверный вид (почта, дата, шаблон); invalid_value —
            значения нет среди допустимых; not_multiple_of — не кратно;
            unrecognized_keys — лишние поля; invalid_union — не подходит ни один
            вид; invalid_key / invalid_element — неверный ключ или элемент;
            custom — своё правило ручки
          example: invalid_format
        message:
          type: string
          description: Текст для человека по-русски — показать под полем
          example: БИН/ИИН — 12 цифр
      required:
        - path
        - code
        - message
      description: Ошибка одного поля запроса
  securitySchemes:
    session:
      type: apiKey
      in: cookie
      name: tungo.session_token
      description: >-
        Сессия кабинета: cookie ставит вход через /v1/auth/* (Better Auth),
        браузер шлёт её сам — фронтенду кабинета ничего добавлять не нужно
        (fetch с credentials: 'include'). За HTTPS имя cookie —
        __Secure-tungo.session_token. Сессия кончилась — 401
        authentication_error: отправить на вход.
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Ключ API организации: `x-api-key: tg_…`. Для серверных интеграций, не
        для кабинета: ключ — секрет, из браузера его не слать (CORS закрыт).
        Какие адреса пускают по ключу — x-api-key-access у операции.
    bearerKey:
      type: http
      scheme: bearer
      bearerFormat: tg_…
      description: 'Тот же ключ API другим заголовком: `Authorization: Bearer tg_…`.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.