Skip to content

How to Schedule Social Media Posts With an API

7 min read

Field names change between providers. The shape does not. Every social media scheduling API worth using follows the same six steps, and the two that cause almost all production problems are the ones tutorials leave out.

This is provider-agnostic. If you want to know which scheduler to build against first, our scheduler API comparison covers eight of them on price and capability. If you would rather not write code at all, the n8n version does the same job with nodes.

Do this before you write any code

Connect the social accounts inside the scheduler’s own web app first.

This is the whole reason to use a scheduler rather than going direct. The scheduler holds the OAuth tokens, refreshes them when Meta expires them roughly every sixty days, and has already cleared the app reviews each platform demands. Going direct means your own App Review with Meta, TikTok’s audit before direct publishing works, and LinkedIn’s partner application with no published timeline. One integration against a scheduler replaces six against platforms that each change independently.

If your product needs your customers to connect their own accounts rather than you connecting yours, that is a different architecture and most scheduler APIs are not built for it. See white-label scheduling for SaaS products instead.

Step 1: authenticate

Most schedulers use a static API key in a header, which is the easy case. Generate it in settings and send it on every request.

Authorization: Bearer YOUR_API_KEY

A few use OAuth for third-party apps, in which case you are exchanging a code for an access token and storing a refresh token. Check which before you design anything, because it changes where credentials live and who owns them.

Keep the key server-side. A scheduler key can usually publish to every connected account, so treating it like a password rather than a configuration value is correct. If the API supports scoped or per-workspace keys, use the narrowest one that does the job.

Step 2: get the account IDs

You post to IDs, not handles. Call the accounts endpoint once and store what comes back.

curl https://api.your-scheduler.com/v1/accounts 
  -H "Authorization: Bearer YOUR_API_KEY"

These IDs are stable, so cache them rather than fetching on every publish. Do refresh them when a post fails with an unknown-account error, which is what you will see after someone disconnects and reconnects an account in the dashboard.

Step 3: upload media first

Media is its own request, and the post references what it returns. Most APIs reject a post whose media is still processing, which is the single most common reason an integration passes testing and fails on real content — your test image was 40KB and the real one is a 60MB Reel.

curl -X POST https://api.your-scheduler.com/v1/media 
  -H "Authorization: Bearer YOUR_API_KEY" 
  -F "file=@reel.mp4"

Keep the returned media ID. For video, poll the media status until it reports ready rather than sleeping for a fixed interval — processing time scales with file size and a hardcoded wait will be wrong in both directions.

Step 4: create the post

One request, with the text, the account IDs, any media, and a publish time.

curl -X POST https://api.your-scheduler.com/v1/posts 
  -H "Authorization: Bearer YOUR_API_KEY" 
  -H "Content-Type: application/json" 
  -d '{
    "accounts": ["acc_instagram_123", "acc_linkedin_456"],
    "text": "New feature is live. Details in the link.",
    "media": ["med_789"],
    "scheduled_at": "2026-11-04T14:00:00Z"
  }'

Send the timestamp as ISO 8601 in UTC, with the trailing Z. This matters more than it looks. A scheduler that silently applies the workspace time zone to a naive timestamp will publish an hour early after a daylight saving change, and nobody notices until a client does. Convert on your side, send UTC, and the bug cannot happen.

If you want the scheduler to pick the time instead of specifying one, that is a queue rather than a schedule, and it behaves differently enough to be worth understanding — see queue APIs versus scheduled posts.

Step 5: confirm it actually published

This is the step most integrations skip, and it is the one that decides whether you find out about failures or your client does.

A 200 on step 4 means the scheduler accepted your post. It says nothing about whether the network took it. That happens later — at the scheduled time, or minutes afterwards — and it can fail then for reasons the scheduler could not have known in advance.

Two ways to close the loop. Subscribe to the provider’s webhook for post status if it has one, which is cheaper and faster. Otherwise poll the post endpoint on a delay and read the status per account.

Read it per account, not per post. The same request can succeed for LinkedIn and fail for Instagram because the image aspect ratio is wrong, and an integration that checks only the post-level status will report success for a post that went out to half its destinations.

{
  "id": "post_abc",
  "status": "partial",
  "results": [
    { "account": "acc_linkedin_456", "status": "published" },
    { "account": "acc_instagram_123", "status": "failed",
      "error": "Unsupported aspect ratio" }
  ]
}

Route failures somewhere a person looks. A message into Slack with the post ID and the provider’s error turns a silent failure into a thirty-second fix; without it you are relying on noticing an absence, which nobody does.

Step 6: handle retries without duplicating

Network calls fail halfway. If your code retries a create-post request that actually succeeded, you have published twice, and duplicate posts are the failure clients notice first.

If the API supports an idempotency key, send one derived from your own content ID and let the provider deduplicate. If it does not, record the returned post ID against your source record in the same transaction that marks it sent, and check that record before any retry.

Rate limits are the other case. Expect 429s when backfilling a month of content, and back off exponentially rather than looping. Most schedulers publish their limits; assume a few requests per second unless told otherwise.

Per-network rules that cause most failures

NetworkWhat catches people out
InstagramNeeds a Business or Creator account. Stories often are not auto-publishable even when feed posts are.
TikTokSounds cannot be attached programmatically, so audio must be in the file. Direct publishing requires the vendor to have cleared TikTok’s audit.
LinkedInPersonal profiles and company pages are separate permissions. Posting for a client page needs the right admin role.
FacebookPages only. No API posts to personal profiles, at any vendor.
YouTubeMostly Shorts. Confirm whether the API sets title, description and thumbnail or leaves them to you.
XThread support varies by vendor because of API pricing. Check it if you post threads.
PinterestNeeds a destination link to be useful, and board handling differs between tools.

Testing without posting to real accounts

Few schedulers have a sandbox. The practical approach is a throwaway set of accounts on a second workspace, or scheduling far enough into the future that you can delete the post before it fires.

Buffer’s free plan covering three channels is the cheapest way to prove an integration works before paying anyone. Publer at $5 for the first account is the cheapest to run one in production. If the API needs to be on the entry plan rather than an agency tier, SchedPilot includes it from $21.

Whatever you test against, test with real media sizes. Almost every failure that reaches production is a file that was bigger or longer than anything in testing.

Frequently asked questions

What format should the publish time be in?

ISO 8601 in UTC, with the trailing Z, for example 2026-11-04T14:00:00Z. Convert from the user’s time zone in your own code. Sending a naive local timestamp and letting the scheduler interpret it is how posts end up an hour out after a daylight saving change.

Why did my post return 200 but never appear?

Because the 200 only confirmed the scheduler accepted it. The network rejected it later, usually over media rules or a permission on that specific account. Read the per-account status rather than the post-level one.

Can I upload the image and create the post in one request?

Some APIs accept a public image URL inline, which works and means the scheduler fetches it. Separate upload is more reliable for video, because you can confirm processing finished before scheduling.

How do I avoid publishing the same post twice?

Send an idempotency key if the API supports one. If not, store the returned post ID against your source record as soon as the call succeeds, and check for it before any retry.

Do I need App Review from Meta to use a scheduler API?

No. The scheduler has already done that, which is most of what you are paying for. App Review applies if you integrate with Meta’s Graph API directly, and commonly runs past a month.

Can I edit or cancel a scheduled post through the API?

Usually yes before it publishes, through a PATCH or DELETE on the post. After publishing, deletion generally removes it from the network too, and editing is not possible on most networks. Confirm the behaviour in your provider’s docs before you build an edit feature on it.

Keep reading

See the full ranking

Every scheduler we have tested, ordered from best to worst, with pricing.

The Best Social Media Schedulers