REST-API v1
Unter /api/v1, angemeldet mit einem API-Schlüssel.
Skripte und KI-Agenten arbeiten in einem Arbeitsbereich mit den Berechtigungen ihres Schlüssels. Jeder Beitrag, den sie anlegen, bekommt die source „api“.
Unter /api/v1, angemeldet mit einem API-Schlüssel.
Unter /mcp (Streamable HTTP), mit API-Schlüssel oder OAuth-Token von claude.ai oder ChatGPT.
calmposts-mcp bietet dieselben Tools über stdio, auf Basis der REST-API.
Die maschinenlesbare Referenz ist https://calmposts.com/api/v1/openapi.json (OpenAPI 3.1, öffentlich).
Der Inhaber des Arbeitsbereichs legt Schlüssel unter „API & MCP“ in der App an und wählt Namen und Berechtigungen. Der Schlüssel (cp_live_…) wird einmal angezeigt; calmposts speichert nur seinen SHA-256-Hash und die ersten 12 Zeichen.
Ein widerrufener Schlüssel wird bei der nächsten Anfrage abgewiesen. Ein Schlüssel hört auch auf zu funktionieren, wenn sein Ersteller gesperrt oder gelöscht wird oder den Arbeitsbereich verlässt. Wie viele Schlüssel möglich sind, legt der Tarif fest; der kostenlose hat keine.
Jede Anfrage sendet Authorization: Bearer cp_live_…. Jeder Schlüssel hat 60 Anfragen pro Minute, REST und MCP zusammen; darüber hinaus lautet die Antwort 429 rate_limited mit Retry-After in Sekunden.
| Berechtigung | Erlaubt |
|---|---|
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 |
Fehler haben ein gemeinsames Format: {"error": "…", "code": "…", "field": "…"}.
Ein Beitrag, der die Prüfung nicht besteht, ist ein 422: field und code nennen das erste Problem (targets[0].parts[0].text, too_long), das Array errors listet alle. Ein Kontingent ist 402 quota_exceeded mit der Metrik als field; eine fehlende Berechtigung 403 insufficient_scope.
Legen Sie den Schlüssel in eine Umgebungsvariable; die Beispiele unten nutzen $auth.
export CALMPOSTS_API_KEY=cp_live_…
export CALMPOSTS=https://calmposts.com
auth=(-H "Authorization: Bearer $CALMPOSTS_API_KEY")Jedes verbundene Konto mit den Regeln seines Netzwerks und seinem Zeichenlimit.
curl "${auth[@]}" $CALMPOSTS/api/v1/accounts
# {"items":[{"id":"…","provider":"x","handle":"@carol","status":"active","char_limit":280,"capabilities":{…}}]}Der Verbrauch des Tarifs in diesem Zeitraum, die Zeitzone des Arbeitsbereichs und die Regeln jedes Netzwerks.
curl "${auth[@]}" $CALMPOSTS/api/v1/limits
# {"timezone":"Europe/Berlin","billing":{"plan":{…},"usage":{"posts_per_day":{"used":3,"limit":30,…}}},"networks":[…]}schedule.mode ist draft, queue (der nächste freie Termin der Konten), at (mit einer Zeit nach RFC 3339) oder now. Mehrere Teile ergeben einen Thread; eigene parts eines Ziels geben diesem Kanal eigenen Text.
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",…}Erst hochladen, dann die Medien-ID in einem Teil übergeben.
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"]}]Filter: status, account_id, from und to (RFC 3339), q, limit und offset.
curl "${auth[@]}" "$CALMPOSTS/api/v1/posts?status=scheduled,failed&limit=20" # {"items":[…],"total":n}
curl "${auth[@]}" $CALMPOSTS/api/v1/posts/POST_IDPATCH ändert, was der Body nennt, ausgehend von der gelesenen Version; eine veraltete Version ergibt 409 version_conflict. Bearbeitbar sind nur Entwürfe und geplante Beiträge.
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 storniert einen geplanten Beitrag (ein erschienener bleibt im Netzwerk). retry sendet die gescheiterten Kanäle sofort erneut. queue/next zeigt, wohin „queue“ einen Beitrag legen würde.
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"}Statt zu pollen, lassen Sie calmposts Ihrem System sagen, was passiert ist. Jede Zustellung ist ein POST mit JSON-Body; die id ist eindeutig, eine Wiederholung lässt sich also verwerfen.
| Ereignis | Gesendet, wenn |
|---|---|
post.published | alle Kanäle eines Beitrags erschienen sind (data: post_id und die url jedes Ziels) |
post.failed | ein Kanal eines Beitrags endgültig gescheitert ist (data: post_id, target_id, error_code, error) |
post.pending_approval | der Beitrag eines Agenten auf die Freigabe durch einen Menschen wartet |
account.needs_reconnect | ein Netzwerk den Zugriff widerrufen hat und das Konto neu verbunden werden muss |
{
"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/…"}]}
}Der Body enthält weder Token noch Geheimnisse.