> ## 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.

# Сценарии компании

> Доступ: company.read.

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



## OpenAPI

````yaml https://api.tungo.kz/v1/openapi.json get /v1/companies/{co}/automations/scenarios
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/companies/{co}/automations/scenarios:
    get:
      tags:
        - Автоматизации
      summary: Сценарии компании
      description: |-
        Доступ: company.read.

        Доступно по ключу API.
      operationId: listCompanyAutomationsScenarios
      parameters:
        - schema:
            type: string
            description: id компании, co_… — из GET /v1/companies
          required: true
          description: id компании, co_… — из GET /v1/companies
          name: co
          in: path
      responses:
        '200':
          description: Сценарии
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AutomationScenario'
                    description: Элементы списка — весь список одним ответом, без страниц
                required:
                  - data
          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
        '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
      security:
        - session: []
        - apiKey: []
        - bearerKey: []
components:
  schemas:
    AutomationScenario:
      type: object
      properties:
        id:
          type: string
          description: id сценария — для адресов …/automations/scenarios/{id} (scn_…)
          example: scn_01jz8x3m4n5p6q7r8s9t0v1w2x
        name:
          type: string
          description: Название сценария
          example: Разнести поступления с сайта
        enabled:
          type: boolean
          description: >-
            Включён ли. Выключенный не запускается событием и расписанием;
            вручную — запускается
        trigger:
          $ref: '#/components/schemas/AutomationTrigger'
        next_run_at:
          type:
            - string
            - 'null'
          format: date-time
          example: '2026-10-05T09:30:00.000Z'
          description: >-
            Когда сценарий по расписанию сработает в следующий раз, ISO 8601
            UTC. null — сценарий ручной, по событию (хука или Tungo) или
            выключен, а у расписания с last_workday — ещё и когда
            производственного календаря сейчас нет (запуск отложен до его
            появления). Пока компания на паузе, запуск в этот срок встанет в
            очередь и начнётся после снятия паузы
        action:
          type: string
          enum:
            - agent
            - checks
            - directbank
          description: >-
            Старая форма: действие (у цепочки — первого шага, полностью —
            steps). `agent` — ход ИИ-бухгалтера по поручению instruction
            (готовит предложения — документы для 1С); `checks` — проверки учёта
            без ИИ и без предложений; `directbank` — опрос выписки DirectBank
            без ИИ (предложения — выпиской дня)
        instruction:
          type: string
          description: >-
            Поручение ИИ обычными словами (первого шага); у checks, directbank и
            цепочки, начатой не с agent, — пустая строка
        output:
          anyOf:
            - $ref: '#/components/schemas/AutomationOutputSpec'
            - type: 'null'
          description: >-
            Форма итога шага ИИ (у сценария из одного шага); null — итог только
            текстом (answer) или сценарий — цепочка
        steps:
          type: array
          items:
            $ref: '#/components/schemas/AutomationScenarioStep'
          description: >-
            Шаги сценария (1–5). У сценария старой формы — один шаг из action,
            instruction и output. Каждый шаг agent — отдельный платный ход ИИ.
        auto_approve:
          anyOf:
            - $ref: '#/components/schemas/AutomationAutoApprove'
            - type: 'null'
          description: >-
            Правило автоодобрения; null — всё подготовленное ждёт решения
            человека
        run_as:
          type: string
          description: >-
            От чьего имени идут запуски — кто сохранил сценарий последним
            (usr_…): с его правами, расход ИИ — как у него
          example: usr_01h455vb4pex5vsknk084sn02q
        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
        - name
        - enabled
        - trigger
        - next_run_at
        - action
        - instruction
        - output
        - steps
        - auto_approve
        - run_as
        - created_at
        - updated_at
      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.
    AutomationTrigger:
      oneOf:
        - $ref: '#/components/schemas/AutomationTriggerHook'
        - $ref: '#/components/schemas/AutomationTriggerSchedule'
        - $ref: '#/components/schemas/AutomationTriggerEvent'
        - $ref: '#/components/schemas/AutomationTriggerManual'
      discriminator:
        propertyName: kind
        mapping:
          hook: '#/components/schemas/AutomationTriggerHook'
          schedule: '#/components/schemas/AutomationTriggerSchedule'
          event: '#/components/schemas/AutomationTriggerEvent'
          manual: '#/components/schemas/AutomationTriggerManual'
      description: >-
        Когда запускается сценарий; вид — в kind (hook, schedule, event,
        manual).
    AutomationOutputSpec:
      type: object
      additionalProperties:
        $ref: '#/components/schemas/AutomationOutputField'
      description: >-
        Форма итога шага ИИ (только action: agent): имя поля → вид и описание,
        от 1 до 20 полей. ИИ в конце хода обязан отдать итог в этой форме; он
        проверяется по ней и приходит в запуске (output) и в вебхуке
        automation.run.completed. Видов значения нет текстовых нарочно: в итоге
        не может оказаться имени, ИИН/БИН, счёта или свободного текста. Не отдал
        или итог не прошёл проверку — output: null и пометка output_error,
        запуск при этом не падает.
      example:
        order_id:
          type: id
          description: Номер заказа из события
        amount_tiyn:
          type: integer
          description: Сумма оплаты в тиынах
        status:
          type: enum
          values:
            - written
            - waiting
          description: written — поступление записано в 1С, waiting — ждёт человека
    AutomationScenarioStep:
      type: object
      properties:
        action:
          type: string
          enum:
            - agent
            - checks
            - directbank
            - notify
          description: >-
            `agent` — ход ИИ (платный); `checks` — проверки учёта; `directbank`
            — опрос выписки DirectBank; `notify` — вебхук automation.run.notice
            разработчику
        when:
          type: string
          enum:
            - always
            - previous_created_proposals
            - checks_found_issues
            - previous_failed
          description: >-
            Когда выполняется шаг: always, previous_created_proposals,
            checks_found_issues, previous_failed
        instruction:
          type:
            - string
            - 'null'
          description: Поручение ИИ (только у agent); null — у шага без ИИ
        output:
          anyOf:
            - $ref: '#/components/schemas/AutomationOutputSpec'
            - type: 'null'
          description: Форма итога (только у agent); null — нет
      required:
        - action
        - when
        - instruction
        - output
      description: Шаг сценария.
    AutomationAutoApprove:
      type: object
      properties:
        kinds:
          type: array
          items:
            type: string
            enum:
              - sale
              - purchase
              - bank_receipt
              - bank_payment
              - counterparty
              - contract
              - inventory_writeoff
              - cash_order_in
              - cash_order_out
              - advance_report
          minItems: 1
          description: >-
            Какие виды документов записываются сами (хотя бы один, без
            повторов). `sale` — реализация товаров и услуг (продажа покупателю);
            `purchase` — поступление товаров и услуг (покупка у поставщика);
            `bank_receipt` — входящее платёжное поручение (деньги пришли на
            расчётный счёт); `bank_payment` — исходящее платёжное поручение
            (оплата со счёта); `counterparty` — новый контрагент (покупатель или
            поставщик) в справочнике 1С; `contract` — новый договор с
            контрагентом (у карточек справочника нет суммы: за запуск сами
            пишутся не больше automations.money.catalog_per_run);
            `inventory_writeoff` — списание товаров; `cash_order_in` — приходный
            кассовый ордер (наличные в кассу); `cash_order_out` — расходный
            кассовый ордер (наличные из кассы); `advance_report` — авансовый
            отчёт сотрудника (на что потрачены подотчётные деньги). Отмена
            документа в список не входит — её всегда решает человек.
          example:
            - bank_receipt
            - sale
        max_amount_per_document_tiyn:
          type: integer
          exclusiveMinimum: 0
          maximum: 1000000000000000
          description: >-
            Потолок суммы одного документа в тиынах (1 ₸ = 100 тиын; 50 000 000
            = 500 000 ₸). Документ дороже, без известной суммы или дороже
            потолка компании (GET …/autonomy) ждёт человека. Не больше
            max_amount_per_day_tiyn.
          example: 50000000
        max_amount_per_day_tiyn:
          type: integer
          exclusiveMinimum: 0
          maximum: 10000000000000000
          description: >-
            Потолок суммы всех автоодобрений сценария за календарный день по
            Алматы, в тиынах. Сверх него документы ждут человека. Сверх этого
            действует и потолок компании на день — общий для всех сценариев и
            выписки DirectBank.
          example: 200000000
        directbank:
          type: boolean
          description: >-
            true — правило применяется и к предложениям, которые собирает опрос
            выписки DirectBank (дополнение документов, созданных 1С из выписки
            банка): после каждого захода опроса ставится запуск этого сценария
            без ИИ, и подходящие предложения записываются сами по этому правилу.
            У компании так может быть только один сценарий. Нет или false —
            выписку DirectBank одобряет человек.
      required:
        - kinds
        - max_amount_per_document_tiyn
        - max_amount_per_day_tiyn
      additionalProperties: false
      description: >-
        Правило автоодобрения: документы, подготовленные в сценарии (по одному
        или пачкой — выписка, входящие ЭСФ), записываются в 1С сами, без кнопки
        «Записать». Записывается только документ: вида из kinds, без блокеров и
        похожих документов, с известной суммой не больше
        max_amount_per_document_tiyn, если с ним сумма автоодобрений за день не
        превысит max_amount_per_day_tiyn и потолок компании, и если владелец
        организации поднял доверие ИИ для этого вида (PUT …/autonomy; иначе
        предложение ждёт). Проводится документ, только если уровень доверия L3,
        иначе пишется черновиком. По событию хука без подписи или без id_path
        само не пишется ничего. Суммы — в тиынах.
    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) — они описаны у этих ручек.
    AutomationTriggerHook:
      type: object
      properties:
        kind:
          type: string
          enum:
            - hook
          description: '`hook` — по событию хука'
        hook_id:
          type: string
          description: Хук, события которого запускают сценарий (hk_…)
          example: hk_01jz8x3m4n5p6q7r8s9t0v1w2x
        filter:
          $ref: '#/components/schemas/AutomationEventFilter'
      required:
        - kind
        - hook_id
      description: Запуск по событию хука.
    AutomationTriggerSchedule:
      type: object
      properties:
        kind:
          type: string
          enum:
            - schedule
          description: '`schedule` — по расписанию'
        schedule:
          $ref: '#/components/schemas/AutomationSchedule'
        timezone:
          type: string
          enum:
            - Asia/Almaty
          description: 'Всегда Asia/Almaty: время в schedule — по Алматы'
      required:
        - kind
        - schedule
        - timezone
      description: Запуск по расписанию.
    AutomationTriggerEvent:
      type: object
      properties:
        kind:
          type: string
          enum:
            - event
          description: '`event` — по событию внутри Tungo'
        event:
          type: string
          enum:
            - proposal.awaiting_approval
            - proposal.written
            - proposal.failed
            - esf.incoming.received
            - bank_statement.received
            - proposal.rejected
            - batch.completed
            - batch.failed
            - onec.connection.changed
          description: >-
            Вид события компании — имя из раздела webhooks этого описания.
            Например: `esf.incoming.received` — пришли входящие ЭСФ;
            `bank_statement.received` — пришла выписка (загружена человеком или
            забрана кнопкой; выписка, забранная сценарием directbank, сценарии
            не запускает — для выписки по расписанию делайте цепочку directbank
            → agent); `proposal.rejected` — человек отклонил предложение;
            `onec.connection.changed` — связь с 1С пропала или вернулась.
            Сценарий берёт только события после своего сохранения; события,
            порождённые запусками автоматизаций, сценарии не запускают — круга
            не будет.
          example: esf.incoming.received
        filter:
          allOf:
            - $ref: '#/components/schemas/AutomationEventFilter'
            - description: >-
                Какие события этого вида запускают сценарий (путь — по телу
                события, как у вебхука: `data.amount_tiyn`); нет — любое
      required:
        - kind
        - event
      description: >-
        Запуск по событию внутри Tungo этой компании: входящие ЭСФ, выписка,
        решение по предложению, связь с 1С.
    AutomationTriggerManual:
      type: object
      properties:
        kind:
          type: string
          enum:
            - manual
          description: '`manual` — только вручную: POST …/scenarios/{id}/run'
      required:
        - kind
      description: Только ручной запуск.
    AutomationOutputField:
      oneOf:
        - type: object
          properties:
            type:
              type: string
              enum:
                - number
              description: '`number` — число'
            description:
              type: string
              minLength: 1
              maxLength: 500
              description: >-
                Что положить в поле — для ИИ, обычными словами (до 500 знаков).
                Пишет разработчик.
              example: Номер заказа из события
          required:
            - type
            - description
          additionalProperties: false
        - type: object
          properties:
            type:
              type: string
              enum:
                - integer
              description: '`integer` — целое число (суммы — в тиынах)'
            description:
              type: string
              minLength: 1
              maxLength: 500
              description: >-
                Что положить в поле — для ИИ, обычными словами (до 500 знаков).
                Пишет разработчик.
              example: Номер заказа из события
          required:
            - type
            - description
          additionalProperties: false
        - type: object
          properties:
            type:
              type: string
              enum:
                - boolean
              description: '`boolean` — да/нет'
            description:
              type: string
              minLength: 1
              maxLength: 500
              description: >-
                Что положить в поле — для ИИ, обычными словами (до 500 знаков).
                Пишет разработчик.
              example: Номер заказа из события
          required:
            - type
            - description
          additionalProperties: false
        - type: object
          properties:
            type:
              type: string
              enum:
                - id
              description: >-
                `id` — номер (заказа, документа, платежа) по шаблону
                ^[A-Za-z0-9_.\-/#]{1,64}$
            description:
              type: string
              minLength: 1
              maxLength: 500
              description: >-
                Что положить в поле — для ИИ, обычными словами (до 500 знаков).
                Пишет разработчик.
              example: Номер заказа из события
          required:
            - type
            - description
          additionalProperties: false
        - type: object
          properties:
            type:
              type: string
              enum:
                - enum
              description: '`enum` — одно значение из списка values'
            description:
              type: string
              minLength: 1
              maxLength: 500
              description: >-
                Что положить в поле — для ИИ, обычными словами (до 500 знаков).
                Пишет разработчик.
              example: Номер заказа из события
            values:
              type: array
              items:
                type: string
                pattern: ^[A-Za-z0-9_.\-/#]{1,64}$
              minItems: 1
              maxItems: 50
              description: >-
                Допустимые значения (1–50, без повторов): латиница, цифры и `_ .
                - / #`, до 64 знаков
              example:
                - written
                - waiting
          required:
            - type
            - description
            - values
          additionalProperties: false
      description: 'Поле итога: вид значения и описание для ИИ.'
    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: Ошибка одного поля запроса
    AutomationEventFilter:
      type: object
      properties:
        all:
          type: array
          items:
            $ref: '#/components/schemas/AutomationFilterCondition'
          maxItems: 20
          description: >-
            Условия (до 20); событие подходит, только если выполнены все. Пустой
            список — подходит любое событие.
      required:
        - all
      additionalProperties: false
      description: Какие события хука запускают сценарий; нет — любое
    AutomationSchedule:
      oneOf:
        - $ref: '#/components/schemas/AutomationScheduleDaily'
        - $ref: '#/components/schemas/AutomationScheduleWeekly'
        - $ref: '#/components/schemas/AutomationScheduleMonthly'
        - $ref: '#/components/schemas/AutomationScheduleInterval'
      discriminator:
        propertyName: kind
        mapping:
          daily: '#/components/schemas/AutomationScheduleDaily'
          weekly: '#/components/schemas/AutomationScheduleWeekly'
          monthly: '#/components/schemas/AutomationScheduleMonthly'
          interval: '#/components/schemas/AutomationScheduleInterval'
      description: >-
        Расписание запуска по Алматы. Пропущенный запуск (сервис был недоступен)
        догоняется одним запуском, а не пачкой за все пропущенные слоты.
    AutomationFilterCondition:
      type: object
      properties:
        path:
          type: string
          pattern: ^[A-Za-z0-9_-]+(\.[A-Za-z0-9_-]+){0,9}$
          description: >-
            Где в JSON тела события взять значение: имена полей через точку, до
            10 уровней; элемент массива — его номером с нуля (`items.0.sum`).
          example: data.status
        op:
          type: string
          enum:
            - eq
            - ne
            - in
            - contains
            - exists
            - gt
            - gte
            - lt
            - lte
          description: >-
            Как сравнивать значение поля с value. `eq` — равно (строки — без
            учёта регистра и пробелов по краям; числа — как числа, строка
            «15000.00» равна 15000); `ne` — не равно, или поля нет; `in` — равно
            одному из значений списка value; `contains` — строка содержит value
            (без учёта регистра) или массив содержит элемент, равный value;
            `exists` — поле есть в теле (с value: false — поля нет); `gt` /
            `gte` / `lt` / `lte` — число больше / не меньше / меньше / не больше
            value (строка из цифр сравнивается как число; не число — условие не
            выполнено).
          example: eq
        value:
          anyOf:
            - type: string
              maxLength: 500
            - type: number
            - type: boolean
            - type: 'null'
            - type: array
              items:
                anyOf:
                  - type: string
                    maxLength: 500
                  - type: number
                  - type: boolean
                  - type: 'null'
              maxItems: 50
          description: >-
            С чем сравнивать: строка (до 500 знаков), число, true/false или
            null. Для `in` — список до 50 таких значений; для
            `gt`/`gte`/`lt`/`lte` — число; для остальных — одно значение. Для
            `exists` не нужно (false — проверить, что поля нет).
          example: paid
      required:
        - path
        - op
      additionalProperties: false
      description: >-
        Одно условие фильтра: значение поля из тела события сравнивается с
        value.
    AutomationScheduleDaily:
      type: object
      properties:
        kind:
          type: string
          enum:
            - daily
          description: '`daily` — каждый день'
        at:
          type: string
          pattern: ^([01]\d|2[0-3]):[0-5]\d$
          description: >-
            Время запуска ЧЧ:ММ (24 часа) по Алматы (Asia/Almaty). Показывать
            как есть, в пояс пользователя не переводить.
          example: '09:00'
      required:
        - kind
        - at
      additionalProperties: false
      description: Каждый день в время at по Алматы.
    AutomationScheduleWeekly:
      type: object
      properties:
        kind:
          type: string
          enum:
            - weekly
          description: '`weekly` — по выбранным дням недели'
        days:
          type: array
          items:
            type: integer
            minimum: 1
            maximum: 7
          minItems: 1
          maxItems: 7
          description: >-
            Дни недели по ISO: 1 — понедельник … 7 — воскресенье; от 1 до 7 дней
            без повторов. День — по календарю Алматы.
          example:
            - 1
            - 2
            - 3
            - 4
            - 5
        at:
          type: string
          pattern: ^([01]\d|2[0-3]):[0-5]\d$
          description: >-
            Время запуска ЧЧ:ММ (24 часа) по Алматы (Asia/Almaty). Показывать
            как есть, в пояс пользователя не переводить.
          example: '09:00'
      required:
        - kind
        - days
        - at
      additionalProperties: false
      description: По выбранным дням недели в время at по Алматы.
    AutomationScheduleMonthly:
      type: object
      properties:
        kind:
          type: string
          enum:
            - monthly
          description: '`monthly` — по числам месяца'
        days:
          type: array
          items:
            type: integer
            minimum: 1
            maximum: 31
          minItems: 1
          maxItems: 31
          description: >-
            Числа месяца 1…31 без повторов. Числа, которого нет в месяце (31 в
            ноябре, 30 в феврале), в этом месяце запуска нет — на последний день
            месяца используйте last_day.
          example:
            - 25
        last_day:
          type: boolean
          enum:
            - true
          description: true — ещё и в последний день месяца (28, 29, 30 или 31-е).
        last_workday:
          type: boolean
          enum:
            - true
          description: >-
            true — ещё и в последний рабочий день месяца по производственному
            календарю РК из базы знаний (выходные и праздники Закона «О
            праздниках в РК»). Оговорка календаря: Учтены выходные (суббота,
            воскресенье) и праздники Закона «О праздниках в РК» с переносом по
            его ст. 5. Переносы рабочих дней и религиозные праздники (Курбан
            айт, Рождество) по ежегодному постановлению Правительства в базе НЕ
            загружены — если срок близок к таким датам, сверьтесь с
            постановлением. Если календаря нет (база знаний недоступна или в ней
            нет праздников), запуск в последний рабочий день откладывается до
            его появления и потом догоняется одним запуском — по одним выходным
            он не считается, чтобы в месяце не вышло двух запусков.
        at:
          type: string
          pattern: ^([01]\d|2[0-3]):[0-5]\d$
          description: >-
            Время запуска ЧЧ:ММ (24 часа) по Алматы (Asia/Almaty). Показывать
            как есть, в пояс пользователя не переводить.
          example: '09:00'
      required:
        - kind
        - at
      additionalProperties: false
      description: >-
        По числам месяца в время at по Алматы. Например, 25-го в 10:00 —
        проверить НДС; последний рабочий день в 18:00 — закрытие месяца.
      example:
        kind: monthly
        last_workday: true
        at: '18:00'
    AutomationScheduleInterval:
      type: object
      properties:
        kind:
          type: string
          enum:
            - interval
          description: '`interval` — каждые N часов в пределах дня'
        every_hours:
          type: integer
          minimum: 1
          maximum: 12
          description: Шаг в часах, 1…12.
          example: 2
        from:
          type: string
          pattern: ^([01]\d|2[0-3]):[0-5]\d$
          description: Первый запуск дня, ЧЧ:ММ по Алматы.
          example: '09:00'
        to:
          type: string
          pattern: ^([01]\d|2[0-3]):[0-5]\d$
          description: >-
            Позже этого времени (ЧЧ:ММ по Алматы) запусков в этот день нет;
            раньше from быть не может.
          example: '19:00'
        days:
          type: array
          items:
            type: integer
            minimum: 1
            maximum: 7
          minItems: 1
          maxItems: 7
          description: >-
            Дни недели по ISO (1 — понедельник … 7 — воскресенье) без повторов;
            нет — каждый день.
          example:
            - 1
            - 2
            - 3
            - 4
            - 5
      required:
        - kind
        - every_hours
        - from
        - to
      additionalProperties: false
      description: >-
        Запуски в from, from + N ч, from + 2N ч … не позже to, в выбранные дни.
        Например, каждые 2 часа с 09:00 до 19:00 по будням — проверить остаток
        на счёте.
      example:
        kind: interval
        every_hours: 2
        from: '09:00'
        to: '19:00'
        days:
          - 1
          - 2
          - 3
          - 4
          - 5
  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.