letmepost / api surfaces / Publishing API
POST /v1/posts

One POST .

Eight platforms. Preflight before postflight.

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.

No credit card · 90-second quickstart →
POST /v1/posts ·
{
  "targets": [
    { "platform": "bluesky" },
    { "platform": "x" },
    { "platform": "pinterest" }
  ],
  "text": "Shipped multi-target publishing today.",
  "scheduledAt": "2026-06-15T19:00:00Z"
}

Why one endpoint instead of eight?

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
One HTTP call publishes everywhere. Idempotency-safe. Preflight-checked. Same shape Bluesky → LinkedIn.

✓ 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

what the endpoint can do
Text posts
Images
Video
Carousels
Scheduled · ISO 8601
Reply chains
Quote posts
Per-platform overrides

HOW IT WORKS

request lifecycle · ~150ms median

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

things the endpoint does that you don't have to build

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.

Pair with the Media API for video and large image uploads.
Media API →

CODE EXAMPLE

multi-target publish with idempotency · typescript
publish-multi.ts ·
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);
  }
}


COMMON QUESTIONS

about the publishing endpoint

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

the rest of the api

LEARN MORE


READY TO POST?

Mint an API key. Send your first request.

* * * POST · ABSTRACTED · DONE * * *
SURFACE · PUBLISHING · /v1/posts
→ START FREE