Post with Python
Same publish contract as the docs quickstart. From Python that's one requests call. Connect accounts once in the dashboard; your code only sends text, addressing, and optional schedule/media.
Get started free →Free tier. No card · one API for every network · full MCP access
You're already in Python (scripts, backends, notebooks) and want social publishing without Tweepy, LinkedIn SDKs, or Meta Graph clients.
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.Connect accounts once in the dashboard, then this is the publish call:
import os
import requests
resp = requests.post(
"https://api.postlake.dev/v1/posts",
headers={
"Authorization": f"Bearer {os.environ['POSTLAKE_API_KEY']}",
"Idempotency-Key": "hello-python-001", # safe retries
},
json={
"text": "Hello from Python 👋",
"profile": "my-brand", # Channels profile name
# Optional filter (not a selector): only these networks under the profile
# "platforms": ["bluesky", "linkedin"],
},
)
resp.raise_for_status()
post = resp.json()
print(post["id"], post["state"])
for t in post["targets"]:
print(t["platform"], t["state"], t.get("url") or t.get("error"))Tool-specific glue on top of the shared setup above:
POSTLAKE_API_KEY (never commit it). Use the profile name from Channels. Same string as in the docs quickstart.requests (or httpx). Omit platforms to hit every account on the profile; add it only to filter networks.targets[]. A top-level partial state means some networks published and some failed. Check each entry.Idempotency-Key so a retry never double-posts.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).platforms only filters accounts already on the profile. It does not create connections.targets on 200 responses with partial/failed.Prefer an assistant over Python code? Point it at MCP (https://api.postlake.dev/mcp). Prefer the dashboard? Use Quickstart → No code.
Create a key and connect accounts under a profile (docs quickstart). Then POST https://api.postlake.dev/v1/posts with Authorization: Bearer sk_live_… and JSON { "text": "…", "profile": "my-brand" }. Read targets[] in the response.
No. One PostLake endpoint covers every connected network. Use requests or httpx only.
Add scheduledAt as UTC (trailing Z), or a naive local time plus timezone (IANA, e.g. Europe/London). Credits charge when it fires. See the scheduling docs.
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 →