Agent content calendar
Round-ups keep sending this job to a calendar app you self-host. That is the wrong default when the agent is the one filling the week. PostLake already queues, timezones, cancels, reschedules, and keeps drafts fail-closed. The dashboard calendar is how a person checks the work. You do not install Postiz to get an agent-driven calendar.
Get started free →Free tier. No card · one API for every network · full MCP access
You want an agent to fill the content calendar, and a person to review it, without self-hosting Postiz or living in a drag-and-drop UI.
Same setup the docs quickstart uses. Do this once:
my-brand) and connect at least one account. Bluesky is the fastest first channel: no app review. Instagram/TikTok/Facebook need each platform's review before API posting.sk_live_…). It shows once; treat it like a password.Same publish contract as the docs, plus scheduledAt, timezone, and draft: true. Credits do not charge until a draft is published and actually fires.
import os, uuid, requests
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
HEADERS = {
"Authorization": f"Bearer {os.environ['POSTLAKE_API_KEY']}",
"Content-Type": "application/json",
}
ZONE = "Europe/London"
def queue_week(items: list[dict]) -> list[dict]:
"""items: [{text, day_offset}] e.g. day_offset=1 is tomorrow 09:00 local."""
out = []
today = datetime.now(ZoneInfo(ZONE)).date()
for i, item in enumerate(items):
when = datetime(
today.year, today.month, today.day, 9, 0, 0
) + timedelta(days=item["day_offset"])
body = {
"text": item["text"],
"profile": "my-brand",
"scheduledAt": when.strftime("%Y-%m-%dT09:00:00"),
"timezone": ZONE,
"draft": True, # nothing ships until you approve
}
r = requests.post(
"https://api.postlake.dev/v1/posts",
headers={**HEADERS, "Idempotency-Key": f"cal-{today}-slot-{i}"},
json=body,
)
r.raise_for_status()
post = r.json()
print(post["id"], post["state"], post.get("scheduledAtLocal"))
out.append(post)
return out
# MCP path (no key in chat): connect https://api.postlake.dev/mcp
# then: "Draft 5 posts for this week from the changelog, adapt length
# per platform, schedule them 24h out as drafts, do not publish until I approve."Tool-specific glue on top of the shared setup above:
https://api.postlake.dev/mcp and approve over OAuth.validate_post (free) before queueing a week, especially for TikTok photos.scheduledAt, timezone, and draft: true. State should be draft. Cost is zero.publish_draft (it keeps the scheduled time unless you clear it).get_analytics / GET /v1/analytics so next week's drafts are not a guess.You get one Post with an overall state and a targets[] array. One entry per account. Always check each target; partial success is normal.
{
"id": "post_a1b2c3",
"state": "partial",
"targets": [
{ "platform": "bluesky", "state": "published", "url": "https://bsky.app/…" },
{ "platform": "linkedin", "state": "failed",
"error": { "type": "invalid_request", "message": "…", "retryable": false } }
]
}published: every target succeeded. partial: some published, some failed. failed: none published. processing: still going (async networks like TikTok).Idempotency-Key header on writes so a retry never double-posts.Same rules as the docs. Pick one addressing style:
"profile": "my-brand" posts to every account under that profile (the name on Channels)."platforms": ["bluesky", "linkedin"] narrows that set. It is a filter, not a selector: if you have two Pinterest boards, both match pinterest."accounts": ["acc_…"] for exact channels (copy an id on Channels, or GET /v1/social-accounts).profile? PostLake uses that profile. Multiple profiles and you omit it? You'll get an error that names them.See Publishing: where to post.
scheduledAt as UTC (trailing Z), or a naive local time plus timezone (IANA, e.g. Europe/London). Credits charge when it fires. Scheduling docs · scheduling guide.POST /v1/media, then pass the med_… id in media. Media docs.textOverrides (e.g. shorter text for X). Per-network options: platformOptions (Pinterest boardId, TikTok privacy, …). Live option lists: GET /v1/platforms/{platform}.POST /v1/posts/validate runs the same checks without publishing (free).timezone is a 400. Trailing Z with no zone still fires at the wrong hour for half the year.Prefer an assistant over AI content calendar code? Point it at MCP (https://api.postlake.dev/mcp). Prefer the dashboard? Use Quickstart → No code.
Connect PostLake's hosted MCP, ask it to draft and schedule the week with timezone, keep posts as drafts, and review them on the dashboard calendar. You do not need to self-host Postiz for this.
If an agent is filling the week: yes. If a person wants to live in a drag-and-drop calendar with RSS and in-app image generation: Postiz is still the better calendar app, and we would rather say so.
Draft 5 posts for this week from the changelog, adapt length per platform, schedule them 24 hours out as drafts, and do not publish until I approve.
Yes, while it is draft or scheduled: PATCH to change copy or time, DELETE to pull it. Cancelling a scheduled post frees the Idempotency-Key.
These guides stay short on purpose. Canonical behaviour lives here:
Also: Media · Errors · MCP · Analytics
All guides · Full docs · llms.txt · Markdown
Stuck? The docs are the source of truth, start at Publishing.
Open the dashboard →