Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.letmepost.dev/llms.txt

Use this file to discover all available pages before exploring further.

Why migrate

Postiz and letmepost are both open-source (Postiz under AGPL-3.0, letmepost under Apache-2.0). The difference is shape: Postiz is a UI-first scheduling app that you self-host as a product for your team, while letmepost is an API-first publishing service for embedding into your own product or agent workflow. If what you actually want is POST /v1/posts with a stable contract, a preflight catalog, structured errors, and SDKs — that’s the surface letmepost ships. Both can run on your own infrastructure. Hosted is available too, if you don’t want to operate either.

What changes

Postiz’s data model is built around posts authored in its scheduler and dispatched to one or more “integrations” (connected accounts). letmepost’s model is a single request that carries one or more targets.
Postiz conceptletmepost conceptNotes
IntegrationPlatform accountConnect via OAuth in the dashboard. Each account has a stable id.
Post (UI-created)POST /v1/posts requestThe API is the primary surface; the dashboard is built on top of it.
Selected integrations on a posttargets[].accountIdMulti-target in one request — same as picking multiple integrations in Postiz.
Scheduled publish datescheduledAt (ISO-8601)Omit for immediate publish.
Media libraryPOST /v1/media then mediaIdUpload once, reference on every post.
Provider-level error in the UIStructured envelope with code, rule, remediation, platformResponse, requestIdSee errors.

API shape side-by-side

Postiz exposes a public REST API for posts when you self-host or use their hosted tier. A typical create-post call schedules content across selected integrations.
curl -X POST https://api.postiz.com/public/v1/posts \
  -H "Authorization: $POSTIZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "schedule",
    "date": "2026-05-20T12:00:00Z",
    "shortLink": false,
    "posts": [
      {
        "integration": { "id": "<integration_id_1>" },
        "value": [{ "content": "Hello", "image": [] }]
      },
      {
        "integration": { "id": "<integration_id_2>" },
        "value": [{ "content": "Hello", "image": [] }]
      }
    ]
  }'
The shapes differ but the intent maps cleanly: Postiz’s posts[].integration.id becomes a targets[].accountId entry on a single letmepost request.

Cutover playbook

1

Sign up and connect your accounts

  • Create an account at dashboard.letmepost.dev, or self-host the same image.
  • Mint an API key (Settings → API keys).
  • Connect each platform you currently publish to from Postiz. letmepost uses each platform’s OAuth flow — same accounts, just re-authorized against letmepost’s app.
  • Copy each connected account’s id from the dashboard; these become your targets[].accountId values.
2

Map your existing payload

  • For every Postiz post that fanned out to N integrations, send ONE letmepost request with N targets entries instead.
  • Replace value[].content with top-level text, and value[].image with media[].
  • Move date to scheduledAt. Omit it for immediate publish.
  • Run the request through preflight — letmepost checks platform-specific constraints (grapheme caps, mime allow-lists, media counts) before the upstream call.
3

Add the idempotency header

letmepost dedupes retries via Idempotency-Key — generate one UUID per logical post and replay safely on network errors. The replay cache returns the original response (same status, same body) for 24 hours. Reusing the same key with a different body returns idempotency_conflict so you catch accidental drift.
4

Handle errors with the new envelope

Postiz surfaces provider errors mostly as messages in the UI. letmepost returns a structured envelope on every failure with code, message, rule, remediation, platformResponse, platformVersion, and requestId. Branch on code and rule, not message text. See errors for the eleven codes and preflight for the rule catalog.
5

Verify with one parallel post

  • For about a week, publish each post through both Postiz and letmepost.
  • Reconcile: same content lands on the same platforms, with the same timestamps and the same media.
  • Once you’re confident, switch traffic over.
6

Decommission your Postiz instance

If you were self-hosting Postiz, you can spin it down (or keep it running for the team’s UI workflow alongside letmepost’s API — they don’t conflict). Both projects are open source; nothing is locked in either direction.

Feature parity

CapabilityPostizletmepost.dev
Open source✓ (AGPL-3.0)✓ (Apache-2.0)
Self-hostable✓ (guide)
Hosted option
Scheduling UIdashboard ships scheduling; UI is intentionally minimal
Public REST API✓ (the primary surface)
Preflight catalog with stable rule ids✓ (preflight)
Structured error envelope (code / rule / remediation / raw platformResponse)✓ (errors)
Request-level idempotency (Idempotency-Key, body-hash conflict)✓ (idempotency)
Pinned platform versions (e.g. Linkedin-Version header, version.deprecated webhook)
Multi-target post in one request✓ (multiple integrations on one post)✓ (targets[])
Official SDKs (TypeScript, Python, Go)community✓ (SDKs)
CLI + MCP server✓ (CLI, MCP)
Built-in AI assistance for draftingnot in scope for v1
Team/workspace UI featuresminimal — v1 is API-first
Analytics dashboardsnot in v1
Postiz is a strong fit if you want an end-user scheduling product. letmepost is a fit if you’re shipping publishing as a capability inside your own app or agent. Many teams will run both.

Need help

Open an issue on GitHub or email rose@letmepost.dev. If you’re migrating from Postiz, we’ll prioritize debugging help.