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
Ayrshare is a closed-source SaaS social media API that has been around for years; it works well for plenty of teams. letmepost is an alternative for teams that want the same kind of API surface with three properties Ayrshare doesn’t offer: open source under Apache-2.0 with a self-host path as an escape hatch, a structured error envelope with stable rule ids and remediation, and request-level idempotency. If those properties matter to you, the migration is mostly a field rename.What changes
Ayrshare’sPOST /post takes a post string, a platforms array, and per-platform options as siblings. letmepost takes a targets array of connected account ids, a top-level text, and a structured media array.
| Ayrshare concept | letmepost concept | Notes |
|---|---|---|
| User Profile (multi-tenant) | API key per workspace | letmepost workspaces map to one set of accounts and one set of keys. |
platforms: ["twitter", "instagram"] | targets[].accountId | Ayrshare resolves the connected account from the profile; letmepost addresses it directly. |
post (string) | text (string) | Same content. |
mediaUrls (array of URLs) | media[].url | letmepost media also supports mediaId (server-side upload) and bytesBase64 (inline). |
scheduleDate | scheduledAt | Both ISO-8601. letmepost requires the timezone offset (Z or +HH:MM). |
Per-platform instagramOptions, twitterOptions, etc. | per-target overrides on targets[] | letmepost places platform-specific fields on the target, not as top-level siblings. |
| Error message string | Envelope: code, rule, remediation, platformResponse, requestId | See errors. |
API shape side-by-side
The biggest shape difference: Ayrshare implicitly picks the right connected account from the profile based on the platform names you list. letmepost has you pass the accountid directly. That’s a deliberate choice — it makes one workspace with multiple accounts on the same platform (e.g. two Instagram Business accounts) addressable without ambiguity.
Cutover playbook
Sign up and connect your accounts
- Create an account at dashboard.letmepost.dev. If you want a self-host escape hatch, see self-host — same image, same contracts.
- Mint an API key (Settings → API keys).
- Connect each platform you currently publish to. letmepost uses each platform’s OAuth flow; you’ll re-authorize the same accounts against the letmepost app.
- Copy each connected account’s
idfrom the dashboard — these become yourtargets[].accountIdvalues.
Map your existing payload
- Translate
platforms: ["twitter", "instagram"]intotargets[]with the corresponding account ids. - Rename
post→text,mediaUrls→media[].url(with akindof"image"or"video"). - Rename
scheduleDate→scheduledAt. letmepost rejects naive datetimes — include theZor an explicit offset. - Move per-platform options (Instagram captions, Twitter alt text, etc.) onto the matching
targets[]entry. See platforms for the per-platform field set. - Run a few candidate posts through preflight — letmepost catches platform-specific issues (grapheme caps, mime allow-lists, media counts, IG reachability) before the upstream call so you don’t waste a publish attempt.
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, which catches accidental drift in your client. Ayrshare does not document a request-level idempotency contract, so if you currently dedupe at all you’re likely doing it in your own code — you can stop.Handle errors with the new envelope
Every letmepost failure carries
code, message, rule, remediation, platformResponse, platformVersion, and requestId. Branch on code and rule, not message text — they’re stable. The raw upstream response is attached when the platform rejected the call, so you don’t lose information when something goes wrong. See errors for the eleven codes and preflight for the rule catalog.Verify with one parallel post
- For about a week, publish each post through both Ayrshare and letmepost.
- Reconcile: same content lands on the same platforms, with the same timestamps and the same media.
- Watch
requestId— every log line, webhook, and error envelope carries it, so a single id traces the whole pipeline end-to-end. - Once you’re confident, switch traffic over.
Feature parity
| Capability | Ayrshare | letmepost.dev |
|---|---|---|
| Hosted REST API | ✓ | ✓ |
| Open source | — | ✓ (Apache-2.0) |
| Self-hostable | — | ✓ (guide) |
| Multi-target post in one request | ✓ (platforms[]) | ✓ (targets[]) |
| Scheduled posts | ✓ | ✓ |
| Preflight catalog with stable rule ids | — | ✓ (preflight) |
Structured error envelope (raw platformResponse attached) | — | ✓ (errors) |
Request-level idempotency (Idempotency-Key, body-hash conflict) | — | ✓ (idempotency) |
Pinned platform versions, version.deprecated webhook | — | ✓ |
| Webhooks for post lifecycle | ✓ | ✓ (webhooks) |
| Analytics endpoints | ✓ | not in v1 |
| Inbox / comments / DMs | ✓ | not in v1 (publisher only) |
| AI content generation | ✓ | not in scope |
| Official SDKs (TypeScript, Python, Go) | ✓ (varies) | ✓ (SDKs) |
| CLI + MCP server | — | ✓ (CLI, MCP) |