Skip to content

How-to

Schedule social media posts via API

One authenticated POST /v1/posts call takes a caption, the accounts to post to and a time. This page walks the whole path, from API key to a confirmed publish.Updated

API hub

1. Get an API key#

API keys are part of the plans that include API access (see pricing). In the SkedCast console, open Settings › Developer and create a key (Owner or Manager only). Give it the posts.compose scope at minimum: a key can never do more than your own role allows, and posts.compose is what POST /v1/posts checks. The full secret is shown once.

2. Build the request#

A post needs four things:

  • clientId: the client (a brand or customer in your workspace) the post belongs to.
  • content: the caption.
  • targets: the connected accounts to post to, as { "mode": "accounts", "accountIds": [...] }. To post to every account of one client, use { "mode": "group", "clientId": "..." }.
  • schedule: { "type": "now" }, { "type": "at", "scheduledAt": "<ISO 8601 UTC time ending in Z>" }, or { "type": "range", "from": "...", "to": "...", "spreadMinutes": 120 }. spreadMinutes (0 to 720, optional) spreads the posts across that many minutes after the chosen time.

All ids are UUIDs. To attach media, upload or import it first, then list the returned ids in mediaIds.

3. Schedule it#

bash
curl -X POST https://api.skedcast.com/v1/posts \
  -H "Authorization: Bearer sked_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "clientId": "00000000-0000-4000-8000-000000000001",
    "content": "Our autumn collection is live.",
    "mediaIds": ["00000000-0000-4000-8000-000000000003"],
    "targets": { "mode": "accounts", "accountIds": ["00000000-0000-4000-8000-000000000002"] },
    "schedule": { "type": "at", "scheduledAt": "2030-01-15T15:00:00Z" }
  }'
POST /v1/posts needs an Idempotency-Key header. A retry with the same key returns the first result instead of creating a second post. Replace the example ids with your own.
json
{
  "data": {
    "postId": "00000000-0000-4000-8000-000000000004",
    "status": "scheduled",
    "targetCount": 1,
    "targets": [
      {
        "targetId": "00000000-0000-4000-8000-000000000005",
        "socialAccountId": "00000000-0000-4000-8000-000000000002",
        "platform": "instagram",
        "status": "scheduled",
        "scheduledAt": "2030-01-15T15:00:00.000Z"
      }
    ],
    "replayed": false
  },
  "meta": { "correlationId": "c-…" }
}
Response (201): one row per destination account.

Scheduling to more than one platform at once#

One content goes to every account named in targets.accountIds, whichever platforms they belong to. When a platform needs a field the caption cannot carry (YouTube's subtitles, Pinterest's board, TikTok's privacy level), add an entry for it to variants and put the field in its overrides. The per-platform pages give the exact fields.

Scheduling many posts in one call#

POST /v1/posts/bulk takes { "items": [ ... ] } with 1 to 50 items, each the same body as POST /v1/posts, and needs an Idempotency-Key. The response is 200 with a created or failed result for each item, in request order, so one bad item does not fail the others. Send validateOnly: true to check the items without creating anything.

Checking what happened#

GET /v1/post-targets/{id} returns the destination's current status. Fields that explain it:

  • error: a readable message when the post did not simply publish.
  • holdReason: while the status is on_hold, the machine-readable reason (the table below). retryAt says when the next try is.
  • outcomeReason: why a missed post missed. Its time passed while it waited; reschedule it.
  • requiredAction: what you must do (reconnect_channel, change_plan, contact_support, reschedule, retry or check_platform), or null when nothing is needed.
  • externalId and permalink: the live post, once it is published. Each platform's page says when permalink is available.

Hold reasons#

holdReasonWhat it means
platform_post_limit, platform_rate_limit, reels_daily_limitThe platform's own limit for this account is reached or it is slowing requests. The post goes out on its own when the limit resets.
platform_app_limit, platform_outage, shared_capacity, app_daily_limit, quota_unconfirmedThe platform is temporarily not accepting this post. It goes out on its own when publishing resumes.
daily_limit, spacing, safe_pace, another_post_publishingSkedCast's per-account pacing is spacing the posts out. The post goes out on its own.
media_preparingThe media is still being processed. The post goes out when it is ready.
plan_upload_limit, x_budgetYour plan's allowance for this platform is used up. The post goes out when the allowance resets, or after you upgrade.
plan_limitThe account is outside your plan's connected-account limit. Keep this account within the limit, or upgrade your plan.
channel_needs_reconnectThe account must be reconnected. The post waits, does not fail, and goes out after you reconnect.
slowed_platform_flag, slowed_failures, slowed_viewsSkedCast has slowed this channel for now to protect it. The post goes out on its own at retryAt.
channel_pausedSkedCast support paused publishing on this channel. Contact support; the post goes out once the pause is lifted.

A held post whose time passes for too long becomes missed; reschedule it. New values can be added over time. Read requiredAction to see whether you need to do anything.

Poll GET /v1/post-targets/{id} for an immediate one-off answer. To avoid polling, subscribe to the target.published and target.failed webhooks (see the webhooks overview).

Common first-call errors#

Status and codeWhat to do
422 validation_failedThe body failed validation. detail names the field.
400 idempotency_key_requiredSend the Idempotency-Key header.
429 rate_limited or 429 tenant_quota_exceededWait the number of seconds in Retry-After, then retry.
502, 503, 504Retry with backoff and the same Idempotency-Key.
500The answer is kept for that key: retry with a new Idempotency-Key.

The full list is in the error reference at /errors, linked under Related reading.

apihow-toscheduling

FAQ

What's the minimum required to schedule a post via API?
clientId, content, targets (at least one connected account) and schedule. Media is optional unless the platform requires it.
Can I schedule to multiple platforms in one API call?
Yes. One POST /v1/posts call sends the same caption to every account named in targets.accountIds, whatever platforms they belong to. Platform-specific fields go in that platform's variants entry, under overrides.
How do I schedule many posts at once via API?
POST /v1/posts/bulk takes an items array of 1 to 50 posts, each the same body as POST /v1/posts. The response is 200 with a created or failed result for each item, in request order. Send validateOnly: true to check the items without creating anything.
What time format does scheduledAt use?
ISO 8601 in UTC, ending in Z, for example 2030-01-15T15:00:00Z.

Ready to broadcast everywhere?

Sign up free — no credit card. You land on the Free plan, and you can start a one-time 7-day Studio trial from your workspace whenever you are ready. Connect your first accounts, import a batch, and watch one post fan out across every platform.