A publishing API that fails loudly.
An open-source publishing API for developers and AI agents. When a post fails, you get the rule that failed, the raw platform response, and a remediation — never an empty body. No per-profile tax.
One endpoint. Any platform.
POST /v1/posts routes to the right platform and runs every
documented rule locally before the upstream call. One request shape,
one error shape, same contract whether you're posting to Bluesky
today or LinkedIn next month.
// Idempotency keys make retries safe.
// Preflight rules run before we hit the platform.
await fetch("https://api.letmepost.dev/v1/posts", {
method: "POST",
headers: {
Authorization: "Bearer lmp_live_…",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
account: { platform: "bluesky", id: "acc_…" },
text: "Shipping letmepost.dev",
}),
}); When it fails, you get something you can act on.
Every failure response is the same shape. Stable code, the rule that fired, the upstream platform version we tried, a remediation hint, a request id you can grep.
{
"error": {
"code": "preflight_failed",
"rule": "bluesky.text.max_graphemes",
"platform": "bluesky",
"platform_version": "atproto-2026-04",
"message": "Post text is 312 graphemes; Bluesky allows at most 300.",
"remediation": "Shorten the post to 300 graphemes or fewer.",
"request_id": "req_01HY6X4AWBJM2K9F2PTQMRD9JQ"
}
} How it works.
Three steps. Minutes, not days.
- 01
Connect an account
One OAuth flow per platform, or an app-password submit for Bluesky. Tokens get AES-256-GCM encrypted at rest. We refresh on the right schedule per platform.
- 02
Send a post
POST /v1/postswith an Idempotency-Key. Preflight rules run locally before the upstream call. If anything fails, you get a rule id and a remediation hint — not abody:. - 03
Subscribe to events
HMAC-signed webhooks for
post.queued,post.published,post.failed,token.expiring, andversion.deprecated. No polling.
Four principles, no exceptions.
Every documented rule — character counts, media formats, audit states, URN patterns — runs locally before the platform sees the request.
No empty { body: {}, message: ""}. Every failure ships
with a stable code, the specific rule that failed, the raw upstream body,
and a remediation hint.
LinkedIn sunset five API versions in six months. We pin the header, track upcoming deprecations, and upgrade internally. Your workflow doesn't break at 2 a.m.
Every write accepts an Idempotency-Key. Retries are safe.
No double-posting loops when a worker restarts mid-publish.
What you can do.
The v1 API surface. Small on purpose — one primitive, done well.
- POST
/v1/postsOne call. Seven platforms at v1. Text, media, carousels — scheduled or now.
- POST
/v1/posts/validateRun preflight without publishing. Test rules in CI. Get every violation back at once.
- POST
/v1/accounts/connect/:platformOne OAuth flow, scoped narrowly. Tokens encrypted at rest. Refresh handled for you.
- GET
/v1/platform-versionsPublic. See which upstream API version we pin per platform and what's deprecating.
- POST
/v1/webhook-endpointsHMAC-signed deliveries for queued, published, failed, token.expiring, version.deprecated.
- GET
/v1/posts/:idFull post record with every attempt, every upstream response, every status transition.
Platform support.
Bluesky first — it forced us to build the token-refresh story for every other platform. The rest follow in the order the data pointed to.
- Bluesky live
- LinkedIn next
- Twitter / X soon
- Instagram soon
- Facebook soon
- Threads soon
- TikTok later
- Pinterest later
YouTube, Reddit, Telegram, Discord, Snapchat, Google Business, and WhatsApp are deliberately not in the v1 scope. See the roadmap for the reasoning.
FAQs.
- What actually works today?
- Bluesky is live end-to-end — connect an account, send a post, get a webhook back. LinkedIn is next (~3 weeks of build). Meta and TikTok are review-gated by the platforms themselves and take 6–12 weeks from app submission. See the plan for dates.
- Why another social media API?
- Because every existing one fails silently and charges per-profile. 2025–26 research across 150+ citations: LinkedIn sunset five API versions in six months; Postiz shipped infinite double-posting bugs; Ayrshare's own docs admit error 138 "masks multiple underlying causes." We fix all three. Read the brief.
- How much does it cost?
- Free during alpha. When hosted billing turns on, it's flat-rate with a real free tier — no per-profile tax, no per-seat lock-in. Self-host stays free forever.
- Is it really open source?
- Apache 2.0 from day one. Same code runs the hosted SaaS and the self-host Docker Compose. No feature gate, no open-core trick.
- Postiz, Zernio, Ayrshare — what's the difference?
- Postiz is OSS but known for silent-failure bugs. Zernio is closed-source (rebranded from Late in late 2025). Ayrshare charges per-profile and returns opaque errors. We ship OSS + transparent errors + flat pricing — nobody else has all three.
- Can I self-host it?
- Yes, first-class. Docker Compose, BYO Postgres and Redis, BYO platform credentials. Same API, same behavior as hosted.
Kick the tires.
Star the repo. Send your first Bluesky post. File an issue when something's weird. We're building in the open.