REST API v1
По адресу /api/v1, вход по API-ключу.
Скрипты и AI-агенты работают в одном рабочем пространстве с теми правами, что выданы их ключу. Все созданные ими посты получают source «api».
По адресу /api/v1, вход по API-ключу.
По адресу /mcp (Streamable HTTP), с API-ключом или OAuth-токеном от claude.ai или ChatGPT.
calmposts-mcp запускает те же инструменты через stdio поверх REST API.
Машиночитаемое описание: https://calmposts.com/api/v1/openapi.json (OpenAPI 3.1, открыто).
Владелец рабочего пространства создаёт ключи в разделе «API и MCP» приложения и задаёт имя и права. Ключ (cp_live_…) показывается один раз; calmposts хранит только его хеш SHA-256 и первые 12 символов.
Отозванный ключ отклоняется на следующем же запросе. Ключ перестаёт работать и тогда, когда его создателя заблокировали, удалили или он вышел из рабочего пространства. Сколько ключей можно держать, задаёт тариф; на бесплатном их нет.
Каждый запрос передаёт Authorization: Bearer cp_live_…. На ключ — 60 запросов в минуту, REST и MCP вместе; сверх этого ответ 429 rate_limited с Retry-After в секундах.
| Право | Разрешает |
|---|---|
accounts:read | GET /accounts, GET /limits |
posts:read | GET /posts, GET /posts/:id, GET /queue/next |
posts:write | POST /posts, PATCH /posts/:id, DELETE /posts/:id, POST /posts/:id/retry |
media:write | POST /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_IDPATCH меняет то, что названо в теле, начиная с прочитанной версии; устаревшая версия — 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/…"}]}
}В теле нет ни токенов, ни секретов.