# Migrate from Ayrshare to the OmniSocials API

> Index of all OmniSocials docs pages: https://docs.omnisocials.com/llms.txt

This guide is for developers who post through the Ayrshare API and want to move to the OmniSocials API. The request shape is close. Ayrshare's `post`, `platforms`, `mediaUrls`, and `scheduleDate` become `content`, `accounts`, `media_urls`, and `schedule_at`. The main change is the account model. Ayrshare picks a user profile with a `Profile-Key` header and links accounts through a link session URL. OmniSocials gives each workspace its own API key, and accounts are connected in the dashboard. Ayrshare facts on this page come from ayrshare.com/docs and were checked on October 21, 2026.

## Concepts

| Ayrshare | OmniSocials | Notes |
|----------|-------------|-------|
| API key (`Authorization: Bearer`) | API key (`Authorization: Bearer omsk_live_...`) | An OmniSocials key belongs to one workspace. |
| User profile and its `Profile-Key` | Workspace and its own API key | There is no `Profile-Key` header. Use the workspace's key instead. |
| `POST /profiles` | Add a workspace in the dashboard | There is no API to create workspaces. |
| Link session or `generateJWT` URL | Dashboard connection | Accounts are connected only in the dashboard, never through the API. |
| One connection per network per profile | One account per channel per workspace | The same model. LinkedIn is the exception, see below. |
| `platforms` values (`twitter`, `gmb`, `linkedin`) | Channel IDs (`x`, `google_business`, `linkedin`, `linkedin_page`) | A workspace can hold a LinkedIn profile and a LinkedIn page at once. |
| Ayrshare post `id` | Post `id` | |
| `postIds[]` with `postUrl` per network | `published_urls` on `GET /posts/{id}` | A map from channel ID to the live URL. |
| Auto Schedule | None | `GET /analytics/best-times` recommends slots. You pick the time. |
| `requiresApproval` | Approval workflows | Pass `approval_workflow_id` with `schedule_at`. See [Creating posts](https://docs.omnisocials.com/creating-posts.md#approval-workflows). |
| Webhook actions | Webhook events | See [Webhooks](#webhooks). |

## Authentication

```text
Ayrshare:    Authorization: Bearer API_KEY
             Profile-Key: PROFILE_KEY
OmniSocials: Authorization: Bearer omsk_live_...
```

With Ayrshare, one API key serves every user profile, and the `Profile-Key` header picks the profile. An OmniSocials key is bound to one workspace, which you choose when you create the key under **Settings → API**. Store one OmniSocials key where you stored each profile key. `GET /accounts` returns `workspace_id` and `workspace_name`, so you can check which workspace a key belongs to.

Ayrshare requires `X-Twitter-OAuth1-Api-Key` and `X-Twitter-OAuth1-Api-Secret` headers on X requests since March 31, 2026. OmniSocials needs no X developer app and no extra headers. Drop them.

Keys have scopes, such as `posts:write` and `media:write`. A key's scopes cannot be edited later. See [Authentication](https://docs.omnisocials.com/authentication.md).

## Endpoint mapping

OmniSocials paths are relative to `https://api.omnisocials.com/v1`. Ayrshare paths are relative to `https://api.ayrshare.com/api`.

| Ayrshare | OmniSocials | Notes |
|----------|-------------|-------|
| `POST /post` | `POST /posts/create` | `POST /posts/create-and-publish` publishes at once. |
| `GET /post/:id` | `GET /posts/{id}` | |
| `GET /history` | `GET /posts` | Filter with `status`. Page with `limit` (max 100) and `offset`. There are no date or platform filters. |
| `PATCH /post` | `PATCH /posts/{id}` | Drafts and scheduled posts only. Any create field can change, including text and media. |
| `DELETE /post` | `DELETE /posts/{id}` | One post per call. Cancels a scheduled publish. A published post stays live on the platforms, see [What is different](#what-is-different). |
| `PUT /post/retry` | `POST /posts/{id}/retry` | Retries only the failed channels, up to 3 times per channel. |
| `POST /media/upload` | `POST /media/upload` | Multipart, up to 100 MB. `POST /media/upload-from-base64` takes base64. |
| `GET /media/uploadUrl` | `POST /media/create-upload-url` | Returns a single-use `upload_url` for 10 minutes. POST a multipart `file` to it, not a `PUT`. |
| `POST /profiles`, `GET`, `PATCH`, `DELETE /profiles` | None | Manage workspaces in the dashboard. |
| `POST /profiles/link-sessions`, `POST /profiles/generateJWT` | None | Connect accounts in the dashboard. |
| `DELETE /profiles/social` | None | Disconnect accounts in the dashboard. |
| `GET /user` | `GET /accounts` | Returns the workspace and its connected accounts, with `status` and `needs_reconnect`. |
| `POST /analytics/post` | `GET /analytics/posts/{id}` | `GET /analytics/posts?ids=` takes up to 100 post IDs. |
| `POST /analytics/social` | `GET /analytics/accounts` | `GET /analytics/overview` gives workspace totals. |
| `GET /comments/:id` | `GET /inbox/conversations?type=comment` | Then `GET /inbox/conversations/{conversationId}/messages`. Needs the opt-in `inbox:read` scope. |
| `POST /comments/reply/:commentId` | `POST /inbox/conversations/{conversationId}/reply` | Pass `message_id` to answer one comment. Needs `inbox:write`. |
| `DELETE /comments/:id` | `DELETE /inbox/messages/{id}` | Instagram, Facebook, and TikTok comments. |
| `POST /comments` | None | `first_comment` posts one comment when the post publishes. |
| `POST /hook/webhook` | `POST /webhooks` | One webhook can subscribe to several events. |
| `GET /hook/webhook` | `GET /webhooks` | |
| `DELETE /hook/webhook` | `DELETE /webhooks/{id}` | |
| `POST /hook/webhook/secret` | `POST /webhooks/{id}/rotate-secret` | The old secret stops working at once. |
| `GET /hook/history` | `GET /webhooks/{id}` | Returns `failure_count` and `last_failure`. There is no full delivery log. |
| `POST /auto-schedule/set` | None | |
| `POST /validate/post` | `POST /media/check` | Checks media against your connected channels. There is no full post validation call. |

## Create a post

The same post in both APIs: one image to Facebook, Instagram, and LinkedIn, with a first comment, scheduled for 08:00 UTC on November 2, 2026.

Ayrshare:

```bash
curl -X POST https://api.ayrshare.com/api/post \
  -H "Authorization: Bearer $AYRSHARE_API_KEY" \
  -H "Profile-Key: $AYRSHARE_PROFILE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "post": "Our autumn collection is live.",
    "platforms": ["facebook", "instagram", "linkedin"],
    "mediaUrls": ["https://example.com/autumn.jpg"],
    "scheduleDate": "2026-11-02T08:00:00Z",
    "firstComment": { "comment": "Shop it at example.com/autumn" }
  }'
```

OmniSocials:

```bash
curl -X POST https://api.omnisocials.com/v1/posts/create \
  -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Our autumn collection is live.",
    "accounts": ["facebook", "instagram", "linkedin"],
    "media_urls": ["https://example.com/autumn.jpg"],
    "schedule_at": "2026-11-02T08:00:00Z",
    "facebook": { "first_comment": "Shop it at example.com/autumn" },
    "instagram": { "first_comment": "Shop it at example.com/autumn" },
    "linkedin": { "first_comment": "Shop it at example.com/autumn" }
  }'
```

If the Ayrshare LinkedIn connection is a company page, use `linkedin_page` instead of `linkedin` in both `accounts` and the first-comment key. The response is a `201` with the post under `data` and `"status": "scheduled"`.

## Field mapping

| Ayrshare field | OmniSocials field | Notes |
|----------------|-------------------|-------|
| `post` | `content` | A string, or an object with `default` and channel keys for per-channel text. |
| `platforms` | `accounts` | Rename `twitter` to `x` and `gmb` to `google_business`. Alias: `channels`. |
| `mediaUrls` | `media_urls` | Up to 10 URLs, 100 MB per file. Or upload first and pass `media_ids`. |
| `isVideo` | None | The type is read from the file. Set `type: "reel"` for TikTok videos, Instagram reels, and YouTube Shorts. |
| `scheduleDate` | `schedule_at` | ISO 8601 in UTC. Alias: `scheduled_at`. |
| `firstComment.comment` | `first_comment` under each channel key | Text only, set per channel. Instagram, Facebook, LinkedIn, YouTube, TikTok, and Telegram. |
| `firstComment.mediaUrls` | None | First comments carry text only. |
| `disableComments` | `tiktok.disable_comment` | TikTok only. |
| `requiresApproval` | `approval_workflow_id` | Requires `schedule_at`. |
| `twitterOptions` | `x` | |
| `instagramOptions` | `instagram` | Location, collaborators, and user tags are top-level fields (`location_id`, `collaborators`, `user_tags`). |
| `faceBookOptions` | `facebook` | |
| `linkedInOptions` | `linkedin` or `linkedin_page` | |
| `youTubeOptions` | `youtube` | For example `youtube.title` and `youtube.privacy_status`. |
| `tikTokOptions` | `tiktok` | |
| `pinterestOptions` | `pinterest` | `pinterest.board_id` is required. |
| `threadsOptions`, `blueskyOptions`, `telegramOptions` | `threads`, `bluesky`, `telegram` | |
| `gmbOptions` | `google_business` | |
| `redditOptions`, `snapChatOptions` | None | Reddit and Snapchat are not live yet. |
| `autoSchedule`, `autoRepost`, `autoHashtag` | None | `hashtag_set` applies a saved hashtag set. |
| `shortenLinks`, `unsplash`, `randomPost`, `randomMediaUrl` | None | |
| `idempotencyKey` | None | Store the returned post `id` and check it before you retry a create. |
| `validateScheduled`, `notes` | None | |

See [Platforms](https://docs.omnisocials.com/platforms.md) for every channel's options.

## Media and scheduling

**Media.** `mediaUrls` maps straight to `media_urls`: OmniSocials downloads each URL and attaches it. Each file can be up to 100 MB. For larger files, call `POST /media/upload-from-url`, which fetches up to 1 GB. Files above about 100 MB come back with `status: "processing"`. Poll `GET /media/{id}` until it is `ready`, then pass the ID in `media_ids`.

Ayrshare's presigned flow takes files up to 5 GB. The largest file OmniSocials takes is 1 GB. A PDF is turned into one image per page. On LinkedIn it publishes as a document. Any media entry can carry alt text as `{ "url": "...", "alt": "..." }`. See [Media](https://docs.omnisocials.com/media.md).

**Scheduling.** `scheduleDate` and `schedule_at` both take an ISO 8601 time in UTC, so the value carries over as is. OmniSocials publishes within one minute of that time. Two behaviors differ:

- A time in the past returns `400 validation_error`. Ayrshare publishes a past `scheduleDate` at once. To publish now, send `publish_now: true`.
- A post with neither `schedule_at` nor `publish_now` is saved as a draft. Ayrshare publishes a post without `scheduleDate` right away.

## Webhooks

Register a webhook with `POST /webhooks` and a list of events. The response returns a `secret` once. Store it.

```bash
curl -X POST https://api.omnisocials.com/v1/webhooks \
  -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/omnisocials",
    "events": ["post.published", "post.failed"]
  }'
```

| Ayrshare action | OmniSocials event | Notes |
|-----------------|-------------------|-------|
| `scheduled` | `post.published`, `post.failed` | OmniSocials sends these for every post, scheduled or not. A partial publish is `post.published` with `data.status` set to `warning`. Check each entry in `data.targets`. |
| None | `post.scheduled` | Sent when a post is scheduled through the API. |
| `social` | None | Poll `GET /accounts` and check `needs_reconnect`. |
| `comments`, `messages`, `mentions` | None | Poll `GET /inbox/conversations` or `GET /inbox/next`. |
| `feed`, `batch`, `automations`, `suspended`, `ads`, `demo` | None | |
| None | `post.approved`, `post.rejected` | Approval workflow outcomes. |

**Signatures.** Ayrshare sends an HMAC-SHA256 of the body in `X-Authorization-Content-SHA256`, with `X-Authorization-Timestamp`. OmniSocials sends `X-OmniSocials-Signature: t=<timestamp>,v1=<hex>`. The HMAC-SHA256 covers the timestamp, a dot, and the raw body, keyed with your webhook secret. Deduplicate on `X-OmniSocials-Delivery`. See [Webhooks](https://docs.omnisocials.com/webhooks.md#verifying-signatures) for verification code.

**Delivery.** Answer with a `2xx` within 10 seconds. Failed deliveries are retried twice, after 2 seconds and then 5 more. After that the event is dropped, so reconcile with `GET /posts?status=` if your endpoint was down. Webhook URLs must use HTTPS.

## Platform coverage

As of October 21, 2026, from ayrshare.com/docs and the [OmniSocials platforms page](https://docs.omnisocials.com/platforms.md).

| Platform | Ayrshare | OmniSocials |
|----------|----------|-------------|
| Facebook | Yes (`facebook`) | Yes (`facebook`), Pages |
| Instagram | Yes (`instagram`) | Yes (`instagram`), Business and Creator accounts |
| Threads | Yes (`threads`) | Yes (`threads`) |
| LinkedIn | Yes (`linkedin`), a profile or a page per connection | Yes, profile (`linkedin`) and company page (`linkedin_page`) |
| YouTube | Yes (`youtube`) | Shorts only (`youtube`) |
| TikTok | Yes (`tiktok`) | Yes (`tiktok`) |
| Pinterest | Yes (`pinterest`) | Yes (`pinterest`) |
| Bluesky | Yes (`bluesky`) | Yes (`bluesky`) |
| X | Yes (`twitter`), with your own X developer app keys | Yes (`x`) |
| Google Business Profile | Yes (`gmb`) | Yes (`google_business`) |
| Telegram | Yes (`telegram`) | Yes (`telegram`), a channel or group |
| Mastodon | Not listed | Yes (`mastodon`) |
| Reddit | Yes (`reddit`) | Coming soon |
| Snapchat | Yes (`snapchat`) | Coming soon |
| WhatsApp | Messaging only | No |

## What is different

- **Account connection.** OmniSocials has no link session or `generateJWT` endpoint. Accounts are connected in the dashboard. If your product lets end users connect their own accounts through your app, OmniSocials does not support that today.
- **No profiles API.** Workspaces are created in the dashboard, and each API key reaches one workspace.
- **Deleting published posts.** `DELETE /posts/{id}` removes the post from OmniSocials only. Ayrshare's `DELETE /post` also removes it from most networks. On OmniSocials, use "Delete from [platform]" on the post in the dashboard, or delete it in the platform's app.
- **X.** OmniSocials needs no X developer app. Posts with a link use prepaid credits. Posts without a link do not. See [X](https://docs.omnisocials.com/platforms/x.md).
- **Rate limit.** OmniSocials allows 100 requests per minute per key. Ayrshare documents 300 requests per 5 minutes per user profile. See [Rate limits and errors](https://docs.omnisocials.com/rate-limits-and-errors.md).
- **Fewer post options.** There is no auto schedule, auto repost, auto hashtag, link shortening, idempotency key, or post validation call. First comments are text only.
- **Times and drafts.** Past times are refused, and a post without a time is a draft.
- **Fewer webhook events.** There are no account, comment, or message events. Failed deliveries are retried twice within seconds, not over hours.
- **File size.** The largest file OmniSocials takes is 1 GB.
- **Error shape.** Ayrshare errors carry `status: "error"` and an `errors` array. OmniSocials errors nest under `error`, with `code`, `message`, and optional `details`. Branch on `error.code`.
- **Fewer channels.** Reddit and Snapchat are not live yet, and YouTube is Shorts only.
- **No test mode.** Neither API documents one. On OmniSocials, use drafts or a workspace with test accounts.
- **What OmniSocials adds.** Mastodon, a LinkedIn profile and page in one workspace, a [Social inbox](https://docs.omnisocials.com/inbox.md) with a next-unanswered queue and comment hiding, approval workflow webhooks, alt text per image, PDF to carousel, hashtag sets, Instagram comment-to-DM automations, and a hosted [MCP server](https://docs.omnisocials.com/mcp-server.md) with OAuth sign-in.

## Migration steps

1. Create an OmniSocials account. Add one workspace for each Ayrshare user profile.
2. Connect each social account in the dashboard, under **Settings → Organisation → Workspaces**. Connect the LinkedIn profile, the LinkedIn page, or both.
3. Create one API key per workspace under **Settings → API**. Start with `posts:write`, `posts:read`, `media:write`, `accounts:read`, and `webhooks:manage`.
4. Replace each profile key in your database with that workspace's OmniSocials key. Remove the `Profile-Key` and X OAuth headers.
5. Change the base URL. Rename the post fields with the [field mapping](#field-mapping) table, and rename `twitter` to `x` and `gmb` to `google_business`.
6. Add `publish_now: true` wherever you posted without `scheduleDate`. Without it, the post is saved as a draft.
7. Register your webhooks with `POST /webhooks`. Swap the signature check and map the actions to events.
8. Recreate the posts that are still scheduled in Ayrshare with `schedule_at`. Then cancel them in Ayrshare with `DELETE /post`, so nothing publishes twice.
9. If you use the `social-media-api` npm package or the `social-post-api` Python package, switch to `@omnisocials/sdk` or `omnisocials`. See [SDKs](https://docs.omnisocials.com/sdks.md).
10. Test with drafts first, since there is no test mode. Then publish one post with `publish_now: true` and check `published_urls` on `GET /posts/{id}`.

:::tip
Ayrshare publishes a post without `scheduleDate` right away. OmniSocials saves it as a draft. Step 6 is the change most likely to be missed.
:::
