calmposts

REST API и вебхуки

Скрипты и AI-агенты работают в одном рабочем пространстве с теми правами, что выданы их ключу. Все созданные ими посты получают source «api».

REST API v1

По адресу /api/v1, вход по API-ключу.

Хостинговый MCP-сервер

По адресу /mcp (Streamable HTTP), с API-ключом или OAuth-токеном от claude.ai или ChatGPT.

Документация MCP

Локальный MCP-бинарник

calmposts-mcp запускает те же инструменты через stdio поверх REST API.

Документация MCP

Машиночитаемое описание: https://calmposts.com/api/v1/openapi.json (OpenAPI 3.1, открыто).

API-ключи

Владелец рабочего пространства создаёт ключи в разделе «API и MCP» приложения и задаёт имя и права. Ключ (cp_live_…) показывается один раз; calmposts хранит только его хеш SHA-256 и первые 12 символов.

Отозванный ключ отклоняется на следующем же запросе. Ключ перестаёт работать и тогда, когда его создателя заблокировали, удалили или он вышел из рабочего пространства. Сколько ключей можно держать, задаёт тариф; на бесплатном их нет.

Каждый запрос передаёт Authorization: Bearer cp_live_…. На ключ — 60 запросов в минуту, REST и MCP вместе; сверх этого ответ 429 rate_limited с Retry-After в секундах.

ПравоРазрешает
accounts:readGET /accounts, GET /limits
posts:readGET /posts, GET /posts/:id, GET /queue/next
posts:writePOST /posts, PATCH /posts/:id, DELETE /posts/:id, POST /posts/:id/retry
media:writePOST /media

Ошибки

У ошибок один формат: {"error": "…", "code": "…", "field": "…"}.

Пост, не прошедший проверку, — это 422: field и code называют первую проблему (targets[0].parts[0].text, too_long), а массив errors перечисляет все. Квота — 402 quota_exceeded с метрикой в field; нет нужного права — 403 insufficient_scope.

Запросы

Подготовка

Держите ключ в переменной окружения; примеры ниже используют $auth.

export CALMPOSTS_API_KEY=cp_live_…
export CALMPOSTS=https://calmposts.com
auth=(-H "Authorization: Bearer $CALMPOSTS_API_KEY")

Аккаунты

Каждый подключённый аккаунт с правилами его соцсети и лимитом символов.

curl "${auth[@]}" $CALMPOSTS/api/v1/accounts
# {"items":[{"id":"…","provider":"x","handle":"@carol","status":"active","char_limit":280,"capabilities":{…}}]}

Лимиты

Расход тарифа за период, часовой пояс рабочего пространства и правила каждой соцсети.

curl "${auth[@]}" $CALMPOSTS/api/v1/limits
# {"timezone":"Europe/Berlin","billing":{"plan":{…},"usage":{"posts_per_day":{"used":3,"limit":30,…}}},"networks":[…]}

Создать пост

schedule.mode — draft, queue (ближайший свободный слот аккаунтов), at (со временем в RFC 3339) или now. Несколько частей — это тред; свои parts у цели дают этому каналу свой текст.

curl -X POST $CALMPOSTS/api/v1/posts "${auth[@]}" -H "Content-Type: application/json" -d '{
  "parts":    [{"text": "Calm posts, scheduled."}],
  "targets":  [{"account_id": "ACCOUNT_ID"}],
  "schedule": {"mode": "queue"}
}'
# 201 {"id":"…","status":"scheduled","scheduled_at":"…","version":1,"source":"api",…}

Приложить картинку

Сначала загрузите файл, потом передайте id медиа в части поста.

curl -X POST $CALMPOSTS/api/v1/media "${auth[@]}" -F file=@cat.png -F alt="A calm cat"
# 201 {"id":"MEDIA_ID","kind":"image",…}  →  "parts": [{"text": "…", "media_ids": ["MEDIA_ID"]}]

Список и чтение

Фильтры: status, account_id, from и to (RFC 3339), q, limit и offset.

curl "${auth[@]}" "$CALMPOSTS/api/v1/posts?status=scheduled,failed&limit=20"   # {"items":[…],"total":n}
curl "${auth[@]}" $CALMPOSTS/api/v1/posts/POST_ID

Изменить

PATCH меняет то, что названо в теле, начиная с прочитанной версии; устаревшая версия — 409 version_conflict. Менять можно только черновики и запланированные посты.

curl -X PATCH $CALMPOSTS/api/v1/posts/POST_ID "${auth[@]}" -H "Content-Type: application/json" \
  -d '{"version": 1, "schedule": {"mode": "at", "at": "2026-10-21T09:30:00+02:00"}}'

Удалить, повторить, следующий слот

DELETE отменяет запланированный пост (вышедший остаётся в соцсети). retry сразу отправляет невышедшие каналы снова. queue/next показывает, куда «queue» поставит пост.

curl -X DELETE "${auth[@]}" $CALMPOSTS/api/v1/posts/POST_ID          # 204
curl -X POST "${auth[@]}" $CALMPOSTS/api/v1/posts/POST_ID/retry      # the post
curl "${auth[@]}" "$CALMPOSTS/api/v1/queue/next?account_ids=A,B"     # {"at":"2026-10-21T09:00:00Z"}

Вебхуки

Вместо опроса API пусть calmposts сам сообщает вашей системе, что произошло. Каждая доставка — POST с JSON-телом; id уникален, так что повтор можно отбросить.

СобытиеКогда приходит
post.publishedвсе каналы поста вышли (data: post_id и url каждой цели)
post.failedканал поста окончательно не вышел (data: post_id, target_id, error_code, error)
post.pending_approvalпост агента ждёт, когда человек его одобрит
account.needs_reconnectсоцсеть отозвала доступ, аккаунт надо переподключить
{
  "id": "…",
  "type": "post.published",
  "workspace_id": "…",
  "created_at": "2026-10-21T09:00:03Z",
  "data": {"post_id": "…", "targets": [{"id": "…", "account_id": "…", "provider": "x", "url": "https://x.com/…"}]}
}

В теле нет ни токенов, ни секретов.

Подключить агента по MCP