One POST .
The primary letmepost endpoint. Send text, media, or scheduled posts to one or many connected accounts in a single HTTP call. 80 preflight rules run locally before the upstream platform is touched. Idempotency keys on every write. Per-target results so you never have to guess whether four succeeded and one didn't.
{
"targets": [
{ "platform": "bluesky" },
{ "platform": "x" },
{ "platform": "pinterest" }
],
"text": "Shipped multi-target publishing today.",
"scheduledAt": "2026-06-15T19:00:00Z"
} Per-platform SDKs
- 8 SDKs, 8 versions, 8 maintainers to keep up with
- 8 different error shapes to unify in your code
- 8 different auth dances to maintain
- 5 LinkedIn sunsets to patch your code through
- No shared idempotency layer
- Postflight failures only, you find out after the call
letmepost Publishing API
- One endpoint, one shape, one auth dance
- One stable error envelope across all platforms
- Idempotency keys handled in the middleware
- Platform versions pinned for you
- 80 preflight rules run before the upstream call
- Per-target outcomes, never an ambiguous boolean
✓ Preflight before postflight
Every documented constraint runs locally before the upstream platform sees the request: character counts, byte caps, media-format checks, audit-state validation, URN patterns, URL reachability. You get the rule id and remediation hint, not an empty body / empty message mystery.
CAPABILITIES
HOW IT WORKS
Validate the envelope
Shape validation against the OpenAPI spec. Wrong type? invalid_request with the JSON path of the bad field. Median latency under 5ms.
Run preflight rules
~80 rules fire per request, scoped to the target platforms. Character counts, byte caps, media-format checks, audit-state validation. Failed preflight returns 422 with the rule id and a remediation hint without ever touching the upstream platform.
Idempotency check
If Idempotency-Key is present and we've seen it in the last 24h, return the cached response. If the body fingerprint differs, return idempotency_conflict (HTTP 409).
Publish to each target in parallel
One upstream call per target. Per-target outcome captured in the response envelope. Webhook post.published fires per-target. Median wall-clock under 2 seconds for a 3-target post.
FEATURES
Preflight, not postflight
Every documented platform constraint runs locally before the upstream call. Fails fast, fails loudly, fails with a doc URL.
Idempotency by default
Idempotency-Key on every write. 24-hour replay window. Body-hash conflict detection on key reuse, surfaced as 409.
Scheduled posts
scheduledAt: ISO8601 queues a delayed job. Returns 202 instead of 201. Webhook post.published confirms the publish when it lands.
Per-platform overrides
pinterest.boardId, x.replyToTweetId, threads.replyToId. Escape hatches without breaking the unified shape.
Per-target outcomes
Never an ambiguous boolean. Each target gets its own status, url, and (on failure) error sub-envelope. Iterate, log, retry per-target if needed.
One auth shape
Bearer-token lmp_live_ or lmp_test_ on every call. We hold the platform tokens, encrypted at rest, refreshed on the right schedule per platform.
CODE EXAMPLE
import { Letmepost } from '@letmepost/sdk'; const lmp = new Letmepost({ apiKey: process.env.LMP_API_KEY }); const result = await lmp.posts.create({ targets: [ { platform: 'bluesky', accountId: 'acc_bsky_xyz' }, { platform: 'x', accountId: 'acc_x_xyz' }, { platform: 'pinterest', accountId: 'acc_pin_xyz', // per-platform override — escape hatch without breaking the shape pinterest: { boardId: '934821023' } }, ], text: 'Shipped multi-target publishing today.', media: [{ mediaId: 'med_01HXZ4N9...' }], // Idempotency-Key stamped automatically by the SDK }); // Per-target outcomes — never an ambiguous boolean for (const r of result.targets) { if (r.status === 'published') { console.log(r.platform, '→', r.url); } else if (r.status === 'failed') { console.error(r.platform, r.error.code, r.error.rule, r.error.docUrl); } }
Publishing API error reference
11 stable error codes plus the 80 preflight-rule identifiers. Each has its own docs page with remediation guidance.
COMMON QUESTIONS
How does multi-target publishing count toward my quota?
One POST /v1/posts = one quota unit, regardless of how many targets. Posting to 8 platforms in a single call counts as 1 post, not 8.
What happens if one target succeeds and another fails?
You get a 200 with a per-target outcome list. The succeeded targets are live, the failed ones have status: "failed" + a full error sub-envelope. Retry the failed targets independently.
Is the Idempotency-Key required?
No, but recommended. Without it, retry-storms can double-post. With it, replays within 24h return the cached response. The SDK stamps one automatically if you don't provide one.
How do I schedule a post?
Add scheduledAt: "2026-06-15T19:00:00Z" (ISO 8601, UTC recommended). Returns 202 instead of 201. We fire post.queued immediately and post.published when it lands.
Can I cancel a scheduled post?
Yes. DELETE /v1/posts/:id while it's still in scheduled state. Returns 204. Cancellations fire a post.canceled webhook.
How fast is the endpoint?
Median request-to-response is ~150ms (preflight + idempotency check + accept). Wall-clock to publish is ~2s for a 3-target post, bound by upstream platforms.
What's the rate limit?
Per-org, not per-key. Burst of 100 requests in 10s, then 1,000/min sustained. Quota wall at your monthly cap. 429 responses carry Retry-After.
Can I dry-run a request?
Yes. POST /v1/preflight runs the rules without publishing. Same response envelope, same error codes. Useful for client-side validation before the actual write.
OTHER SURFACES
LEARN MORE
READY TO POST?
Mint an API key. Send your first request.