PostFast API

Programmatically schedule and publish posts across 11 social platforms, upload media, and read analytics. REST over HTTPS, authenticated with a single workspace API key.

https://api.postfa.st/Auth: pf-api-key

Quickstart: a 200 in under 2 minutes

  1. Generate a workspace API key from Workspace Settings (requires an ADMIN role).
  2. Send it in the pf-api-key header.
  3. Make a cheap read to confirm it works: list your connected accounts.
curl -X GET "https://api.postfa.st/social-media/my-social-accounts" \
  -H "pf-api-key: YOUR_WORKSPACE_API_KEY"
See GET /social-media/my-social-accounts ->

To try the API without writing code, fork the PostFast API collection on Postman and paste your key into its pf_api_key variable.

API Endpoints

Social Media Account Management

GET/social-media/my-social-accounts

Retrieves a list of social media accounts connected to the workspace associated with the API key. Each account includes its latest daily follower or subscriber count.

GET/social-media/{socialMediaId}/follower-history

Returns daily follower/subscriber snapshots for one connected account, plus the current count and the net change over the range. Build growth charts without storing your own snapshots. The latest count is also on GET /social-media/my-social-accounts.

GET/social-media/search-places

Search real-world places (restaurants, venues, hotels, landmarks) to geotag on Facebook and Instagram posts. The returned id works as both facebookPlaceId and instagramLocationId.

GET/social-media/{socialMediaId}/pinterest-boards

Retrieves all Pinterest boards for a connected Pinterest account. Use the boardId field when setting pinterestBoardId on a Pinterest post.

GET/social-media/{socialMediaId}/youtube-playlists

Retrieves all YouTube playlists for a connected YouTube account. Use the playlistId field when setting youtubePlaylistId on a YouTube post.

GET/social-media/{socialMediaId}/gbp-locations

Returns all synced Google Business Profile locations for a connected account. Use the locationId field as gbpLocationId when creating GBP posts.

GET/social-media/{socialMediaId}/tiktok-sounds

Returns TikTok's trending, pre-cleared sounds for a connected TikTok account, ranked by a genre, country, and time window you choose. Use the musicSoundId field as tiktokMusicSoundId when creating a TikTok photo carousel or video post.

POST/social-media/connect-link

Generates a secure connect link that lets someone connect their social accounts to your workspace without a PostFast account. Can be scoped to specific platforms and return the user to your own app when done. Optionally emails the link.

Social Post Management

I. Authentication

Overview

All API requests must be authenticated using an API key specific to your workspace. The API key must be included in the request headers as pf-api-key.

Generating an API Key

Users with an ADMIN role in a workspace can generate an API key from the Workspace Settings page within the PostFast web application. Each API key is uniquely tied to a single workspace and grants access only to the social media accounts connected within that specific workspace. This key is then used for authenticating your REST API requests.

Example Header:

pf-api-key: YOUR_WORKSPACE_API_KEY

Rate Limiting

Rate limits are counted per endpoint, per workspace API key. Calls to one endpoint never use another endpoint's budget, so reaching the limit on one endpoint does not slow down the others.

Every endpoint has four windows: 1 minute, 5 minutes, 1 hour, and 24 hours. Exceeding any of them returns a 429. Each endpoint page lists the windows that endpoint sets itself; any window it does not set uses the default below.

Default Limits (Per Endpoint)

  • 72 requests per minute
  • 180 requests per 5 minutes
  • 360 requests per hour
  • 2,400 requests per day

For example, DELETE /social-posts/:id sets 200 requests per hour, so it allows 2,400 requests per day, 200 per hour, 180 per 5 minutes, 72 per minute.

How the Windows Work

  • A window starts at the endpoint's first call, not on a clock boundary. The 24-hour window is not a reset at midnight UTC.
  • Once a window is exceeded, that endpoint stays blocked for the full length of the window from that moment: up to 60 seconds for the minute window and up to 24 hours for the daily one.
  • Calls made while blocked still count toward the window, so retrying early can keep the endpoint blocked.

Rate Limit Headers

Every response carries one set of headers per window, named short (1 minute), medium (5 minutes), long (1 hour), and daily (24 hours). The first call to an endpoint on the default minute and 5-minute limits returns, among others:

X-RateLimit-Limit-short: 72
X-RateLimit-Remaining-short: 71
X-RateLimit-Reset-short: 60
X-RateLimit-Limit-medium: 180
X-RateLimit-Remaining-medium: 179
X-RateLimit-Reset-medium: 300

Header meanings:

  • X-RateLimit-Limit-[window]: The endpoint's limit for that window
  • X-RateLimit-Remaining-[window]: Requests left in the window
  • X-RateLimit-Reset-[window]: Seconds until the window resets

Rate Limit Exceeded (429 Response)

When a window is exceeded, the response carries a retry header named after that window, plus the standard Retry-After with the same value:

Retry-After-long: 2395
Retry-After: 2395
{
  "statusCode": 429,
  "message": "Too many requests. Please try again later.",
  "error": "Too Many Requests"
}
  • Retry-After: Seconds to wait before calling this endpoint again, up to 60 for the minute window and up to 86,400 for the daily one. This is the standard header, and the one to read if your HTTP client, n8n or Zapier handles back-off for you.
  • Retry-After-[window]: The same value, named after the window that was exceeded (for example Retry-After-long). Useful for telling which limit you hit.

Staying Inside the Limits

  • Read the X-RateLimit-Remaining-[window] headers and slow down before one reaches 0.
  • On a 429, wait Retry-After seconds before calling that endpoint again. Retrying earlier still counts toward the window.
  • Don't poll the account list or the post list in a tight loop.

Error Responses

Common HTTP status codes you might encounter:

  • 400 Bad Request - The request was malformed (e.g., missing required fields, invalid JSON). Check the response body for specific error messages. Also returned when scheduling a post to a social account that is currently DISABLED (revoked/expired token or suspended account); reconnect it in the PostFast app first.
  • 401 Unauthorized - The API key is missing, invalid, or not authorized for the workspace.
  • 403 Forbidden - The API key is valid, but does not have permissions for the requested action (e.g., trying to access resources of another workspace).
  • 404 Not Found - The requested resource could not be found (e.g., tiktokSounds.socialMediaNotFound when the account is not a TikTok account in your workspace). Deleting a post never returns 404: an unknown id answers 200 with { "deleted": false }.
  • 429 Too Many Requests - You have exceeded the rate limit for the endpoint.
  • 500 Internal Server Error - An unexpected error occurred on our server.

III. Typical Workflow: Scheduling Posts with Media

  1. Authentication: Ensure you have a valid pf-api-key for your workspace.
  2. (Optional) Identify Target Account: Call GET /social-media/my-social-accounts to list available social media accounts and retrieve the id of the account you want to post to. Store these IDs as they are generally stable.
  3. Request Signed URLs for Media: If your posts include media:
    • Call POST /file/get-signed-upload-urls with the contentType (e.g., image/png) and count.
    • Receive a response containing an array of { key, signedUrl } objects.
  4. Upload Media to S3: For each media item:
    • Perform an HTTP PUT request to the signedUrl.
    • The request body must be the raw file data.
    • The Content-Type header of this PUT request must match the contentType used in the previous step.
    // Upload file to S3 using the signed URL from previous step  
    const fs = require('fs');
    const file = fs.readFileSync('/path/to/your/image.png');
    
    const response = await fetch(signedUrl, {
      method: 'PUT',
      body: file,
      headers: {
        'Content-Type': 'image/png' // Must match contentType from step 1
      }
    });
    
    if (response.ok) {
      // File uploaded successfully
      // Use the 'key' from step 1 in your social posts
    }
  5. Create the Social Posts:
    • Call POST /social-posts.
    • In the request body, include an array of posts in the posts field, each containing content, scheduledAt, and socialMediaId.
    • If media was uploaded, populate the mediaItems array for each post using the key(s) from step 3 (e.g., image/a1b2c3d4-e5f6-7890-1234-567890abcdef.png). Ensure the type field ('IMAGE' or 'VIDEO') matches the key prefix.
    • Optionally include controls for platform-specific settings.