Sayweek für Entwickler: API und MCP
Verbinde Sayweek mit Claude oder ChatGPT, oder nutze die REST-API. Jeder Schreibzugriff legt einen Entwurf an, der auf deine Freigabe wartet.
Claude & ChatGPT (MCP)
Sayweek ist ein Remote-MCP-Server (Streamable HTTP, OAuth 2.1). Die URL:
https://app.sayweek.com/api/mcp
- claude.ai: Einstellungen → Connectors → „Add custom connector“ → URL einfügen → Connect → bei Sayweek anmelden → Erlauben.
- ChatGPT: Einstellungen → Apps & Connectors → Advanced → Developer mode → Create → die URL, Authentication: OAuth.
Claude Code:
claude mcp add --transport http sayweek https://app.sayweek.com/api/mcp
Werkzeuge für den Assistenten
list_brands– Marken und Kanäleget_week_plan– Slots und Posts der Wocheget_calendar_context– wo du sein wirst und was für ein Tag es ist (aus dem Kalender, ohne Termintitel)list_posts, list_ideas, get_analytics_summary– lesencreate_post_draft, update_post, add_idea– Entwürfe und Ideengenerate_week_drafts, get_generation_job– Sayweek schreibt die Entwürfe der Woche in der Stimme der Markeapprove_post– echte Planung – nur mit der Berechtigung „approve“ und eingeschalteten Freigaben
Authentifizierung
Jede Anfrage: Authorization: Bearer <token>. Der Token ist ein API-Schlüssel (pp_…, Einstellungen → Integrationen → Claude & ChatGPT) oder ein OAuth-Access-Token (sw_at_…, 1 Stunde gültig, erneuerbar). Tokens werden nur gehasht gespeichert; ein Passwort-Reset widerruft Assistenten-Verbindungen.
OAuth 2.1: Authorization Code + PKCE (S256), dynamische Client-Registrierung (RFC 7591), Metadaten unter /.well-known/oauth-authorization-server und /.well-known/oauth-protected-resource.
Berechtigungen (Scopes)
read– Marken, Kanäle, Plan, Posts, Ideen, Kalender-Übersicht, Statistikwrite– Entwürfe schreiben/bearbeiten, Ideen, Woche generieren, nicht gesendete Posts löschenapprove– freigeben = wirklich einplanen; muss auch im Workspace erlaubt sein, alle Freigaberegeln gelten
Solo: nur read. Pro, Team und Agency: auch write und approve.
Endpunkte
| GET | /api/v1/brands | read |
| GET | /api/v1/channels?brand_id= | read |
| GET | /api/v1/posts?from=&to=&status=&brand_id=&cursor= | read |
| POST | /api/v1/posts | write |
| GET | /api/v1/posts/{id} | read |
| PATCH | /api/v1/posts/{id} | write |
| DELETE | /api/v1/posts/{id} | write |
| POST | /api/v1/posts/{id}/approve | approve |
| GET | /api/v1/ideas?status=new | read |
| POST | /api/v1/ideas | write |
| GET | /api/v1/week?start=YYYY-MM-DD | read |
| POST | /api/v1/generate | write |
| GET | /api/v1/jobs/{id} | read |
| GET | /api/v1/calendar/sources?days=14 | read |
| GET | /api/v1/analytics/summary?days=30 | read |
Vollständige Referenz (OpenAPI 3.1): https://app.sayweek.com/api/v1/openapi.json
Beispiele
curl
# Next week's plan
curl https://app.sayweek.com/api/v1/week?start=2026-10-05 \
-H "Authorization: Bearer $SAYWEEK_KEY"
# A draft (never published by the API)
curl -X POST https://app.sayweek.com/api/v1/posts \
-H "Authorization: Bearer $SAYWEEK_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: draft-2026-10-06-linkedin" \
-d '{"channel_id":"<channel id>","date":"2026-10-06","text":"…","hashtags":["#sayweek"]}'
# Let Sayweek write next week (async job)
curl -X POST https://app.sayweek.com/api/v1/generate -H "Authorization: Bearer $SAYWEEK_KEY"
curl https://app.sayweek.com/api/v1/jobs/<job id> -H "Authorization: Bearer $SAYWEEK_KEY"JavaScript
const api = (path, init = {}) =>
fetch(`https://app.sayweek.com/api/v1${path}`, {
...init,
headers: { Authorization: `Bearer ${process.env.SAYWEEK_KEY}`, "Content-Type": "application/json", ...init.headers },
}).then(async (r) => {
const body = await r.json();
if (!r.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
return body;
});
const { data: brands } = await api("/brands");
const job = await api("/generate", { method: "POST", body: JSON.stringify({ brand_ids: [brands[0].id] }) });
const status = await api(`/jobs/${job.id}`);
console.log(status.status, status.done, "/", status.total);Fehler, Seiten, Limits
Fehlerformat: { "error": { "code", "message", "details" } }. Listen: { data, next_cursor } – nächste Seite: ?cursor=<next_cursor>. Limits pro Client und Minute: 120 Lesezugriffe, 30 Schreibzugriffe, 6 Generierungen (429 + Retry-After). Bei POST spielt ein Idempotency-Key-Header 24 Stunden lang die erste Antwort erneut aus.