Вызовы, которые можно скопировать сверху вниз. Все они идут на https://api.coremind.ru и подписываются одним заголовком Authorization: Bearer cmk_… — как именно устроен ключ, описано в аутентификации. Все имена полей в запросах и ответах — snake_case.
0. Получить ключ
Войдите на сайт, откройте личный кабинет и в блоке «API-ключи» нажмите «Создать ключ». Ключ показывается один раз при создании — сразу сохраните его, например в переменную окружения COREMIND_API_KEY. Чтение, каталог и цены доступны и без тарифа, а для запуска генераций у аккаунта должен быть активный тариф.
1. Проверить ключ
GET /v1/whoami отвечает тем, во что разрешился ключ: user_id, key_id и scopes — список областей, которыми ключ располагает. Если этот вызов прошёл, ключ и заголовок собраны верно.
curl -s https://api.coremind.ru/v1/whoami \
-H "Authorization: Bearer cmk_..."2. Узнать аккаунт
GET /v1/me не принимает ни одного параметра: субъект берётся из ключа, чужой аккаунт прочитать нельзя. Ветвиться здесь обычно нужно по plan.id, по credits.main_cc — баланс в сантикредитах, как и все кредитные числа этого API, — и по free_quotas[].remaining.
Бесплатные генерации тарифа доступны через API. Строки free_quotas с mode: "unlimited" бесплатны только в очереди: передайте в запросе promo_mode: "queue", иначе генерация спишет кредиты. Доступность безлимитных генераций через API не гарантируется — что доступно прямо сейчас, показывает GET /v1/me → free_quotas.
curl -s https://api.coremind.ru/v1/me \
-H "Authorization: Bearer cmk_..."3. Получить каталог
GET /v1/models перечисляет модели, которые этот ключ может запустить. Модели типов, которые API не отправляет, выключенные модели и модели раннего доступа без доступа в список не попадают: чего в нём нет, то отправлять не нужно. Запись модели несёт id, type, constraints — что модель требует на входе — и pricing, где у каждого варианта цены указана единица, в которой она посчитана: цена за секунду и цена за ролик — разные числа. Полный перечень полей — в справочнике. Необязательный ?type= сужает выдачу.
curl -s "https://api.coremind.ru/v1/models?type=video" \
-H "Authorization: Bearer cmk_..."Справка и гайды по промптам лежат рядом, под той же областью models:read. GET /v1/knowledge?q=&limit= ищет по заголовку и краткому описанию и отвечает в конверте с next_cursor: null: выдача ограничена limit, а не разбита на страницы. Без q приходят только первые limit материалов в редакционном порядке, а не вся база: конкретную статью находят поиском по её словам. GET /v1/knowledge/{slug} отдаёт одну статью целиком. Здесь только публичные статьи и гайды, в том языке, на котором они написаны, — его называет поле lang. Неизвестный или непубличный slug одинаково отвечает not_found.
4. Прочитать свои генерации
Коллекция — GET /v1/generations — отвечает конвертом { data, next_cursor }: next_cursor нужно передать обратно без изменений в ?cursor=, а null означает, что страниц больше нет. Границы limit и правила курсора — на странице лимитов. Одну генерацию целиком читает GET /v1/generations/{id}, и форма записи там та же, что в списке.
curl -s "https://api.coremind.ru/v1/generations?limit=20" \
-H "Authorization: Bearer cmk_..."5. Следить за генерациями
За продвижением генераций следят по потоку событий GET /v1/events: каждая смена статуса приходит в него сама, и спрашивать ничего не нужно. Как подключиться и переподключаться без потерь — на странице событий.
POST /v1/generations/status — способ добрать пропущенное: после оборванного потока, который не удалось продолжить, или после кадра reset. Он принимает до 50 идентификаторов за раз и возвращает те же записи в data — спрашивайте только о тех, что не дошли до конечного статуса; одну генерацию перечитывает GET /v1/generations/{id}. Конечен DONE: результат готов и уже не изменится. QUEUED, PENDING, RUNNING и MODERATION_PENDING означают, что работа продолжается. FAILED завершает попытку, но не запись: если провайдер ответит с опозданием, та же генерация может перейти в DONE вместе с output_urls и refunded — поток сообщит и об этом. Весь словарь status опубликован в справочнике. Это чтение, а не запись: обоим маршрутам нужна область generations:read.
curl -s -X POST https://api.coremind.ru/v1/generations/status \
-H "Authorization: Bearer cmk_..." \
-H "Content-Type: application/json" \
-d '{"ids": ["<generation_id_1>", "<generation_id_2>"]}'Каждая ссылка в output_urls ведёт на сам API — GET /v1/generations/{id}/outputs/{kind}/{index} — и отдаёт файл только с тем же заголовком Authorization: без ключа владельца по ней ничего не скачать. Берите ссылку как есть, не собирайте её сами.
6. Библиотека
GET /v1/library/assets перечисляет загруженные референсы вызывающего, новые первыми, в том же конверте { data, next_cursor } и с теми же ?cursor= и ?limit=. У записи есть kind, размеры, folder_id и expires_at: загрузка живёт не вечно, и это поле говорит, до какого момента. GET /v1/library/folders параметров не принимает — папок у аккаунта ограниченное число, поэтому маршрут отвечает всем списком сразу, а next_cursor там всегда null. Обоим маршрутам нужна область library:read. Сам файл референса отдаёт GET /v1/library/assets/{id}/content — эта ссылка и лежит в output_urls записи.
curl -s "https://api.coremind.ru/v1/library/assets?limit=20" \
-H "Authorization: Bearer cmk_..."
curl -s https://api.coremind.ru/v1/library/folders \
-H "Authorization: Bearer cmk_..."Разложить библиотеку можно тем же ключом с областью library:write: POST /v1/library/folders создаёт папку, PATCH /v1/library/folders/{id} меняет её name или position, DELETE /v1/library/folders/{id} удаляет только саму папку — её содержимое возвращается в корень. POST /v1/library/move переносит item_ids в folder_id, а null там означает корень. Заголовок меняют PATCH /v1/library/assets/{id} у референса и PATCH /v1/generations/{id} у генерации. Кредитов эти маршруты не тратят. Чужой идентификатор отвечает not_found, как и несуществующий. Переполненная библиотека — 409 folder_limit_reached, уже занятое имя папки — 409 folder_name_taken.
7. Загрузить референс
Свой файл отдаётся хранилищу напрямую, а не нам: POST /v1/uploads подписывает ровно один PUT и возвращает url, headers, reference и expires_at. Маршруту нужна отдельная область uploads:write; кредиты он не тратит. Ответ — 200, а не 201: объекта ещё нет, он появится, когда вы выполните PUT.
expires_at здесь — срок годности самой подписи, а не файла: после него этот url перестаёт приниматься хранилищем, и нужен новый билет. Сколько проживёт уже загруженный файл, говорит expires_at его записи в GET /v1/library/assets — это другое поле и другой отсчёт, поэтому истёкшую подпись нельзя читать как признак того, что reference больше не годится.
В запросе kind, content_type и content_length, и все три проверяются до того, как подпись вообще появится. Подписывается kind: "image"; остальные медиа отвечают 503 с кодом upload_unavailable. Разрешённые типы — image/jpeg, image/png, image/webp, video/mp4, video/quicktime, video/webm, audio/mpeg, audio/mp3, audio/wav, audio/wave, audio/x-wav, audio/ogg, audio/aac; потолок размера — 40 МиБ, и точное число в байтах повторяется в тексте отказа. content_length — не максимум, а точная длина: подпись закрепляет именно её.
SIZE=$(wc -c < reference.jpeg)
curl -s -X POST https://api.coremind.ru/v1/uploads \
-H "Authorization: Bearer cmk_..." \
-H "Content-Type: application/json" \
-d '{"kind": "image", "content_type": "image/jpeg", "content_length": '"$SIZE"'}'
# в ответе url, proxy_path, headers, reference и expires_at — этот PUT идёт мимо нас, в хранилище
# длина подписана вместе с адресом: другое число — и хранилище откажет
curl -s -X PUT "<url>" \
-H "Content-Type: image/jpeg" \
-H "Content-Length: $SIZE" \
-H "If-None-Match: *" \
--data-binary @reference.jpegPUT нужно выполнить ровно с теми заголовками, что пришли в headers: подпись связывает их, и на расхождении хранилище отвечает 403. Билет записывает свой адрес один раз, поэтому повторный PUT по тому же url получает 412 — если загрузку нужно повторить, берите новый билет. Загруженный файл сразу учтён в библиотеке аккаунта.
Если прямой PUT до хранилища не доходит — так бывает в сетях, которые режут этот хост на теле чуть крупнее нескольких десятков килобайт, — тот же билет можно закрыть через нас: PUT /v1/uploads/content с тем же Content-Type и теми же байтами в сыром теле. Адрес уже собран в поле proxy_path ответа POST /v1/uploads, выбирать между путями по гео не нужно: оба выдаются сразу, берите тот, который проходит. Область та же — uploads:write.
SIZE=$(wc -c < reference.jpeg)
# тот же билет, но через наш хост — в ответе это поле proxy_path
curl -s -X PUT "https://api.coremind.ru<proxy_path>" \
-H "Authorization: Bearer cmk_..." \
-H "Content-Type: image/jpeg" \
-H "Content-Length: $SIZE" \
--data-binary @reference.jpeg
# {"reference": "<reference>", "bytes_stored": <SIZE>}Билет пишет один раз, каким бы путём вы им ни воспользовались, поэтому повторное завершение здесь отвечает 409 duplicate_key_conflict — это тот же запрет, что и 412 от хранилища на прямом url, просто на него отвечает другая сторона. Тип и точную длину задаёт билет: расхождение отказывается, а не сохраняется.
Дальше в дело идёт reference — это то, что отправляется обратно при генерации, например в image_urls. Сами байты проверяются при отправке генерации, а не при загрузке: подпись здесь не означает, что файл принят.
8. Узнать цену заранее
POST /v1/pricing/estimate принимает то же самое тело, что и отправка генерации, и отвечает, во что она обойдётся: price_cc в сантикредитах, model_id, а в breakdown — variant (какая строка цены сработала), units (на что умножена ставка) и surcharge_cc (что добавлено сверху). Цену считает та же функция, которая потом спишет.
price_cc — это потолок, а не точное списание: бесплатная квота и промо-режим отрабатывают после расчёта и могут только уменьшить сумму. Маршрут ничего не создаёт и не тратит, ему хватает области models:read. Повтор ничего не создаёт и не списывает, но расходует общий лимит запросов, как любой вызов /v1.
Там, где цена зависит от файла — длительности трека или клипа, размера картинки для апскейла, — оценка измеряет сам файл на сервере, как это сделает списание, поэтому файл должен уже существовать и читаться; иначе ответ — 400, а не число. Запрос с promo_mode оценить нельзя: ответ будет 422 с кодом estimate_unavailable, а не придуманное число. Какие значения модель вообще принимает, публикует GET /v1/models: тело, которое отправка отвергнет, эта оценка отвергает тоже. Модель, которой нет в каталоге, оценка не считает, а тип, который API не принимает, получает тот же 503 с кодом submit_unavailable, что и отправка.
Числа в ответе ниже взяты для образца:
curl -s -X POST https://api.coremind.ru/v1/pricing/estimate \
-H "Authorization: Bearer cmk_..." \
-H "Content-Type: application/json" \
-d '{"type": "image", "model": "<model_id>", "prompt": "..."}'
# {"type": "image", "model_id": "<model_id>", "currency": "credits",
# "price_cc": 1200, "breakdown": {"variant": "default", "units": 1, "surcharge_cc": 0}}9. Прочитать биллинг
GET /v1/billing/transactions перечисляет движения кредитов аккаунта, новые первыми, в конверте { data, next_cursor } с теми же ?cursor= и ?limit=. amount_cc — знаковое число в сантикредитах: положительное пополняет баланс, отрицательное списывает. У списания за генерацию заполнен generation_id — тот самый id, который принимает GET /v1/generations/{id}; у записей без такой связи, в том числе у старой истории, там null.
GET /v1/billing/subscription отвечает действующей подпиской в поле subscription или null, если её нет, — не 404. Суммы там в целых единицах currency, а не в сантикредитах. Тариф, баланс и бесплатные квоты здесь не повторяются — их отдаёт GET /v1/me. Платежи через API не видны и не создаются. Обоим маршрутам нужна область billing:read.
curl -s "https://api.coremind.ru/v1/billing/transactions?limit=20" \
-H "Authorization: Bearer cmk_..."
curl -s https://api.coremind.ru/v1/billing/subscription \
-H "Authorization: Bearer cmk_..."Управление подпиской на сайте
В спецификации также описаны действия личного кабинета. Они доступны только с сессионной cookie сайта: API-ключ и OAuth-токен получают 403 insufficient_scope, в том числе с областью billing:read. Для этих действий откройте страницу подписки в личном кабинете.
POST /v1/subscription/resume— возобновить автопродление; ответ содержитnext_pay_date.POST /v1/subscription/cancel— отключить автопродление. Тело принимает необязательныеreasonиreason_text; ответ содержитplan_ends_atиsuperseded— признак того, что тариф уже продлевает новая подписка.POST /v1/subscription/card-change— начать смену карты и получитьpayment_idс параметрами платёжного виджета.POST /v1/subscription/card-change/complete— завершить смену карты после виджета. Тело содержитpayment_idи необязательныйtransaction_id; ответ —card,next_pay_date,resumedиcharge, результат оплаты просроченного периода.
10. Написать в поддержку
У аккаунта один тред поддержки, и это тот же чат, что открывается на сайте. GET /v1/support/messages отвечает им целиком в data, а next_cursor там всегда null; если обращений ещё не было — пустым списком, не 404. Чтение отмечает тред прочитанным, как открытие чата. У сообщения from — user или support, а text приходит ровно в том виде, в каком его написали.
POST /v1/support/messages отправляет в тот же тред text и до трёх картинок в images — это reference из POST /v1/uploads, не ссылки. client_msg_id — UUID, который вы придумываете сами: повтор с ним после потерянного ответа вернёт уже отправленное сообщение, а не создаст второе. Как устроен этот повтор, описано в идемпотентности. Чтению нужна область support:read, отправке — support:write; кредиты не тратит ни то, ни другое.
curl -s https://api.coremind.ru/v1/support/messages \
-H "Authorization: Bearer cmk_..."
curl -s -X POST https://api.coremind.ru/v1/support/messages \
-H "Authorization: Bearer cmk_..." \
-H "Content-Type: application/json" \
-d '{"text": "...", "client_msg_id": "<uuid>"}'Инструкция для агента
Чтобы код против API писал Codex или Claude Code, вставьте блок ниже в AGENTS.md (Codex) или CLAUDE.md (Claude Code) в корне проекта. Он направляет агента на llms.txt — оглавление документации для агентов: это соглашение, и сами ни Codex, ни Claude Code его не ищут. Если агент должен не писать код, а генерировать сам, ему нужен не этот блок, а MCP-сервер.
## CoreMind API
Перед тем как писать код, прочитай:
- https://coremind.ru/llms.txt — оглавление документации
- https://coremind.ru/docs/api/openapi.json — спецификация OpenAPI: маршруты, поля, коды ответов
Правила:
- Адрес сервера https://api.coremind.ru, пути маршрутов уже начинаются с /v1. Каждый запрос — с заголовком Authorization: Bearer <ключ>. Ключ бери из переменной окружения COREMIND_API_KEY и никогда не записывай в файлы.
- Модели и допустимые значения полей бери из GET /v1/models, не придумывай.
- Перед POST /v1/generations вызывай POST /v1/pricing/estimate с тем же телом и показывай цену пользователю до траты кредитов. Если оценка ответила 422 с кодом estimate_unavailable (так отвечает запрос с promo_mode), цену заранее узнать нельзя: скажи об этом пользователю и отправляй только с его согласия.
- POST /v1/generations отправляй с заголовком Idempotency-Key: новый UUID на каждую новую генерацию, тот же ключ с тем же телом — на повтор после сбоя сети.
- Смену статуса генераций получай из потока GET /v1/events, а запись читай через GET /v1/generations/{id}. POST /v1/generations/status — только чтобы добрать пропущенное после обрыва потока или кадра reset, не для опроса.
- При ошибке ветвись по error.code, а не по тексту и не по одному HTTP-статусу. Что значит каждый код и что делать дальше, описано в https://coremind.ru/docs/api/error-codes.Что дальше
- Аутентификация — свойства ключа и словарь областей доступа.
- OAuth для приложений — доступ от имени другого пользователя вместо ключа.
- Идемпотентность — обязательный
Idempotency-Keyна отправке генерации и повторы на остальных записывающих маршрутах. - События (SSE) — поток смены статусов, переподключение по
Last-Event-IDи его лимиты. - Лимиты и квоты — частота запросов, размер страницы, кеширование.
- Коды ошибок — по чему ветвиться, когда вызов не прошёл.
- Справочник — полная спецификация всех маршрутов и схем.
- MCP-сервер — чтобы агент генерировал сам, без кода против API.