Postify API documentation

REST API v1 for programmatic scheduling and publishing. Base URL https://app.usepostify.com/v1.

5-minute quickstart

  1. Mint an organization API key at Settings → API keys (org owners and admins only). Keys start with postify_live_ and are shown once — store the secret immediately.
  2. Make your first call — list the channels you can publish to:
curl https://app.usepostify.com/v1/channels \
  -H "Authorization: Bearer postify_live_XXXXXXXXXXXXXXXX"
200 OK · application/json
{
  "data": [
    {
      "id": "ch_9x2y3z0001",
      "platform": "linkedin",
      "handle": "acme-co",
      "display_name": "Acme Co",
      "status": "connected"
    },
    {
      "id": "ch_9x2y3z0002",
      "platform": "bluesky",
      "handle": "acme.bsky.social",
      "display_name": "Acme",
      "status": "connected"
    }
  ]
}

3. Use a channel's id to create your first post — as a draft, scheduled, or published now.

Authentication

Send your key on every request, either way:

  • Authorization: Bearer postify_live_
  • x-api-key: postify_live_

Keys are organization-scoped: they see exactly the workspace they were minted in. Each key carries the scopes chosen at mint — every operation page lists the scope it requires.

posts:readView your posts and drafts
posts:writeCreate and edit posts
channels:readSee your connected social channels
channels:writeManage channel connections
analytics:readView analytics
webhooks:readView webhooks
webhooks:writeManage webhooks
ai:generateUse AI generation (consumes your AI credits)

Errors

Every error is RFC 9457 application/problem+json. Branch on the stable code; the type URI resolves to a docs page for that exact code. Validation errors add an errors array with per-field paths.

400 Bad Request · application/problem+json
{
  "type": "https://usepostify.com/docs/api/problems/validation-failed",
  "title": "Request validation failed",
  "status": 400,
  "code": "validation_failed",
  "detail": "1 field failed validation.",
  "errors": [
    { "path": "variants.0.channel_id", "message": "Required" }
  ],
  "request_id": "req_6f1f8a2b40d34cd2a6f1e2c9b8d7a601"
}

All 14 codes: error-code index.

Pagination

List endpoints return { data, has_more, next_cursor }. Pass limit (1–100) and after — a previous page's next_cursor — to walk the collection. Cursors are opaque; never parse them.

Idempotency

POST /v1/posts accepts an Idempotency-Key header (1–255 printable ASCII characters — use a UUID). The ledger keeps keys for 24 hours:

  • Same key + same body → the recorded response replays verbatim, with Idempotency-Replayed: true.
  • Same key + different body → 422 idempotency_key_reused.
  • Same key while the first attempt still runs → 409 idempotency_in_progress — wait and retry the same key.

Rate limits & plan quotas

Two independent limits, with distinct 429 codes so your retry logic can be correct: rate_limited (per-key burst — honor Retry-After) and quota_exhausted (monthly plan allowance — retrying is pointless until the period resets).

PlanAPI requests / monthPer-key burst / minute
Free1,00030
Starter10,00060
Team50,000120
Agency250,000300

Every API-key response carries IETF draft-11 rate-limit headers plus the X-RateLimit compatibility trio:

RateLimit-Policy: "per-key-minute";q=120;w=60
RateLimit: "per-key-minute";r=73;t=38
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1800000038

Dangerous operations

DELETE /v1/posts/{id} and POST /v1/posts/{id}/publish can destroy content or publish publicly to real accounts, so they answer 403 dangerous_ops_disabled until a workspace owner enables "Dangerous AI operations" in Settings → API keys. Drafts and scheduled posts need no toggle — the recommended agent flow is draft by API, publish by human.

All operations

More