Skip to main content
In 90 seconds you’ll publish to X (Twitter) from your terminal. The same POST /v1/posts shape works for every platform we support — Twitter is the entry-point because most developers already think in tweets.
Twitter and Bluesky are live today. The remaining platforms (Instagram, LinkedIn, Facebook, Threads, Pinterest) are gated on their developer-portal reviews and turn on as approvals clear. Same API, same error envelope, same idempotency contract — substitute any connected accountId below if you’re starting on a different platform.

1. Get an API key

Sign in at dashboard.letmepost.dev and mint a key from the API keys page. Keys look like lmp_live_… (production) or lmp_test_… (sandbox). Treat them like passwords; the dashboard only shows the secret once.
export LMP_KEY=lmp_live_...

2. Connect Twitter

Open the dashboard’s Accounts page and click Connect X / Twitter. The OAuth 2.0 PKCE flow is fully handled for you — you grant scopes once and we manage refresh transparently afterwards. When you come back, the account row will show the connected handle and an id you’ll send posts against.
Each platform has its own connect flow (OAuth, PKCE, or app password for Bluesky). They’re all documented per platform under Platforms, but the dashboard is the easiest path for the first connection — it manages redirects and stores tokens encrypted.
Copy the connected account’s id from the dashboard. You’ll need it in the next step.

3. Send a tweet

curl -X POST https://api.letmepost.dev/v1/posts \
  -H "Authorization: Bearer $LMP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{
  "targets": [
    { "accountId": "00000000-0000-0000-0000-000000000000" }
  ],
  "text": "Hello from letmepost.dev"
}
EOF
Replace the accountId with the id you copied from the dashboard. The active language tab is sticky — picking TypeScript here will follow you across every code sample on this site.

4. Read the response

A successful immediate publish returns 200 OK with a batch envelope:
200.json
{
  "id": "batch_01HY6X4AWBJM2K9F2PTQMRD9JQ",
  "status": "published",
  "createdAt": "2026-05-16T12:00:00.000Z",
  "results": [
    {
      "accountId": "00000000-0000-0000-0000-000000000000",
      "platform": "twitter",
      "postId": "post_01HY6X4...",
      "status": "published",
      "uri": "https://x.com/yourhandle/status/1788..."
    }
  ]
}
The results[].uri is the public URL of the tweet. Save id (the batch id) and results[].postId — that’s how you fetch the record later via GET /v1/posts/:id.

5. Fan out to multiple platforms

Same call, more targets. One request, N publishes, atomic shape preflight, structured per-target results:
curl -X POST https://api.letmepost.dev/v1/posts \
  -H "Authorization: Bearer $LMP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{
  "targets": [
    { "accountId": "<twitter_account_id>" },
    { "accountId": "<linkedin_account_id>" },
    { "accountId": "<bluesky_account_id>" }
  ],
  "text": "Hello from three platforms at once"
}
EOF
The batch status summarizes the outcomes: published when every target succeeded, partial_failed on mixed outcomes, failed when none did. Each results[] entry tells you what happened on that platform.

6. What happens when it fails

Send a 400-character tweet and you’ll get this back instead:
400.json
{
  "error": {
    "code": "preflight_failed",
    "rule": "twitter.text.max_graphemes",
    "platform": "twitter",
    "message": "Post text is 400 graphemes; Twitter (free tier) allows at most 280.",
    "remediation": "Shorten the post to 280 graphemes, or switch to a Premium-tier account (25,000 cap).",
    "docUrl": "https://docs.letmepost.dev/errors/preflight_failed",
    "ruleUrl": "https://docs.letmepost.dev/preflight/twitter-text-max_graphemes",
    "requestId": "req_01HY6X4AWBJM2K9F2PTQMRD9JQ"
  }
}
Every error carries the same envelope: stable code, the rule that fired, a remediation, a requestId you can grep, and docUrl / ruleUrl links straight to the right docs page. See errors for the full catalog and error best practices for the contract.

Next

Platforms

Twitter, Instagram, LinkedIn, Facebook, Threads, Pinterest, Bluesky — caps, scope sets, and per-platform wisdom.

Idempotency

Why every retry is safe.

Errors

The twelve codes and the rule catalog.

API reference

POST /v1/posts parameter by parameter.