Skip to content
Reading with an AI assistant?View as MarkdownOpen in ClaudeOpen in ChatGPT

Get started

REST API conventions: pagination and errors

This REST API pagination and errors guide covers the conventions every SkedCast endpoint shares: response envelopes, keyset (cursor) pagination, idempotency keys for safe retries, correlation IDs for support requests, and the RFC 9457 problem+json error format. Learn them once and they apply across the whole API.

Browse docs

6 min read

Response envelopes#

Single resources return { data, meta }. Collections return { data, page, meta }. meta.correlationId is the request's trace id — include it when contacting support.

json
{
  "data": [ { "object": "client", "id": "…" }, … ],
  "page": { "cursor": null, "nextCursor": "eyJ…", "hasMore": true },
  "meta": { "correlationId": "c-…" }
}
List envelope.

REST API pagination#

Lists use keyset (cursor) pagination — stable under inserts and fast at any depth. Pass limit (1–100) and the nextCursor from the previous page as cursor. Iterate until hasMore is false.

bash
curl "https://api.skedcast.com/v1/posts?limit=50&cursor=eyJ…" \
  -H "Authorization: Bearer sked_live_YOUR_KEY"

Idempotency#

Every mutating request — POST, PATCH and DELETE — must carry an Idempotency-Key header (any unique string — a UUID is ideal). Replaying the same key returns the original result instead of creating a duplicate, so a network retry is always safe.

Standard headers#

HeaderDirectionPurpose
AuthorizationrequestBearer sked_… (API key) or Bearer <token> (OAuth)
Idempotency-KeyrequestRequired on POST, PATCH and DELETE; dedupes retries
X-Correlation-IdbothTrace id; echoed in meta.correlationId
RateLimit-*responseYour budget, what is left, and seconds to reset (on a 429: Retry-After)

Rate limits#

Programmatic access is limited per client: each API key or OAuth app has its own request budget for the minute, set by your plan (below). A batch request counts one unit per item, so a call that creates 50 posts uses 50 units. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until the window resets); a 429 adds Retry-After. Read those headers and back off — don't hard-code delays.

The MCP server has one shared budget per connected client, and a tighter share of it for the tools that delete or cancel (delete a client, campaign or webhook, cancel a post, and the batch action that can cancel many at once). Scheduling and publishing are ordinary writes and use the shared budget only. The 429 says which budget ran out, so an agent can back off on that class alone.

A token is only charged for what it could actually do: a call to a delete, cancel or batch tool that the token's scopes or role do not allow costs the ordinary one unit, so a read-only token cannot use up the allowance your other tokens share. In Settings → Developer, each API key has a Usage view showing its requests and refused requests per day and over the last 24 hours, next to the budget it is counted against.

You can also set a WRITE limit on an individual API key, or on a connected app for your whole workspace, in Settings → Developer. Reads keep your plan's budget; only writes — anything that is not a GET on the REST API, and any tool that changes something over MCP — draw on it. A batch counts its items, and a bulk action counts the destinations it touches, so one call that cancels 500 posts uses 500. A write limit can only tighten your plan's budget, never raise it, so it is a way to let a new agent read freely while it publishes carefully. Leave it unset and nothing changes. A 429 from a write limit says which budget ran out; note that a refused request still counts toward your plan's overall budget, so back off rather than retrying immediately.

Separately, every route has an outer per-IP bound against abuse, and first-party credential endpoints (sign-in and password reset) are tighter at 10 requests per minute per IP. What is actually published still respects each platform's own limits and your plan's post caps, however fast you call.

PlanAPI requests / minMCP requests / minMCP destructive / min
SoloNot included6010
Studio1206020
Agency30012040
Agency+60024080
Enterprise1200480160

Per API key or OAuth app, per minute. Every response sends `RateLimit-Limit` / `RateLimit-Remaining` / `RateLimit-Reset`; a 429 adds `Retry-After`.

Errors#

Errors are RFC 9457 application/problem+json. Every error carries a stable machine code, an HTTP status, a human title/detail, and the correlationId. Validation failures (422) add a per-field errors array.

json
{
  "type": "https://skedcast.com/errors/validation_failed",
  "title": "Validation failed",
  "status": 422,
  "category": "bad-body",
  "code": "validation_failed",
  "detail": "One or more fields are invalid.",
  "correlationId": "c-…",
  "errors": [ { "path": "content", "message": "Required" } ]
}
Error shape.

Status codes#

StatusMeaning
400 / 422Malformed request / validation failed
401Missing or invalid credentials
403Authenticated but lacking the scope/role
404Resource not found
409Conflict (idempotency or state)
429Rate limited — back off per Retry-After
5xxTransient/server error — safe to retry
conventionspaginationerrorsidempotency

FAQ

Why keyset pagination instead of page numbers?
Keyset (cursor) pagination is stable when rows are inserted or deleted mid-iteration and stays fast at any depth, unlike offset pagination. Just follow nextCursor until hasMore is false.

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.