Skip to content
PostyAPIv0.3.81
Menu

Posty API reference

Programmatic access to Posty workspaces: posts, approvals, comments, channels, media, campaigns, client shares, questionnaires, analytics, link in bio, inbox, Today and members. Authenticate with an API key or a Better Auth OAuth access token with mcp:tools scope. OAuth requests require X-Workspace-Id, except GET /v1/workspaces.

Base URL
https://api.posty.social
Format
JSON over HTTPS
OpenAPI document
openapi.json
List your workspaces
curl "https://api.posty.social/v1/workspaces" \
  -H "Authorization: Bearer $POSTY_API_KEY"

Authentication

Send an API key as a bearer token: Authorization: Bearer pk_live_.... Team owners and admins create keys on the API keys page in Posty. A key works while its workspace is on a plan that includes API access.

A key is scoped to one workspace or to its whole team. A team key must name the workspace on every request, with the workspaceId query parameter or the X-Workspace-Id header. GET /v1/workspaces lists the workspaces a key can reach.

Each key keeps the scopes it was created with. A request outside those scopes answers 403 with the code missing_scope. AI clients connect through OAuth instead of a key; see the MCP server guide.

Name a workspace
curl "https://api.posty.social/v1/posts?workspaceId=$WORKSPACE_ID" \
  -H "Authorization: Bearer $POSTY_API_KEY"

Errors

Failed requests answer with a 4xx or 5xx status and an error object. Branch on type for the broad class and on code for the exact cause. Quote requestId when you contact support.

TypeStatusMeaning
authentication_error401The key is missing, invalid, expired or revoked.
permission_error402, 403The key lacks a scope, the plan does not include the feature, or a limit is reached.
invalid_request_error400A parameter or body field failed validation.
not_found_error404The resource does not exist in the selected workspace.
conflict_error409The resource is in a state that does not allow the change, or an idempotent request is still running.
rate_limit_error429Too many requests. Wait for the Retry-After seconds.
api_error500Something failed on our side. Retry POST requests with the same Idempotency-Key.

Error object

  • errorobjectrequired
    Child attributes
    • typestringrequired

      One ofauthentication_errorpermission_errorinvalid_request_errornot_found_errorconflict_errorrate_limit_errorapi_error

    • codestringrequired

      One ofauthentication_requiredinvalid_api_keyapi_key_expiredapi_key_revokedapi_key_orphanedmissing_scopevalidation_failedinvalid_scheduleinvalid_channelinvalid_mediaduplicate_channel_contentstorage_limit_exceededpost_limit_exceededworkspace_inactiveworkspace_requiredworkspace_not_foundworkspace_mismatchplan_not_eligiblemedia_not_uploadedpost_not_editablepost_not_foundchannel_not_foundmedia_not_foundcomment_not_foundinvalid_transitionapproval_requiredchannel_inactivemedia_not_readyresource_not_foundlimit_exceededfeature_not_availablecampaign_not_foundpersona_not_foundobjective_not_foundquestionnaire_not_foundresponse_not_foundlink_not_foundtemplate_not_foundblock_not_foundconversation_not_foundpost_thread_not_foundinvitation_not_foundmember_not_foundlast_workspace_admintoday_item_not_founduser_session_requiredfolder_not_foundreview_request_not_foundcampaigns_disabledcampaign_archivedcampaign_status_conflictinvalid_campaign_windowpersona_not_in_campaignpost_not_in_campaignshare_not_foundcampaign_limit_exceededquestionnaire_archivedquestionnaire_not_activequestionnaire_limit_exceededresponse_not_submittedmember_limit_exceededchannel_limit_exceededhandle_unavailableoperating_model_not_agencydelegated_connect_not_availableorganization_not_foundidempotency_key_in_useidempotency_in_progressrate_limit_exceededinternal_error

    • messagestringrequired
    • paramstring
    • docUrlstring
    • requestIdstringrequired
Error response
{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "content must contain at least 1 item",
    "param": "content",
    "requestId": "req_8f2c1e0b"
  }
}

Pagination

List endpoints return a list object. Ask for up to 100 items with limit (20 by default). When has_more is true, pass next_cursor as starting_after to fetch the next page.

List response
{
  "object": "list",
  "data": [
    {
      "id": "post_123"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJpZCI6InBvc3RfMTIzIn0"
}

Idempotency

Add an Idempotency-Key header (up to 255 characters) to any POST to make retries safe. A successful response is stored for 24 hours, and a retry with the same key and body gets it back with Idempotent-Replayed: true instead of running again.

The same key with a different body answers 409 idempotency_key_in_use. A retry that arrives while the first request is still running answers 409 idempotency_in_progress; try again shortly. Failed requests are not stored, so they can be retried with the same key.

Retry safely
curl -X POST "https://api.posty.social/v1/posts" \
  -H "Authorization: Bearer $POSTY_API_KEY" \
  -H "Idempotency-Key: 6f1c9a52-launch-post" \
  -H "Content-Type: application/json" \
  -d '{"content":[{"channelId":"$CHANNEL_ID","body":"Hello"}]}'

Rate limits

Each key can make 600 GET requests and 120 other requests per minute. Unauthenticated traffic is limited to 60 requests per minute per IP address.

Responses carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). Over the limit, requests answer 429 with a Retry-After header in seconds.

Resources