PostFast API Documentation

Welcome to the PostFast API! Integrate our social media scheduling power into your applications.

Table of Contents

Introduction

The PostFast REST API allows you to programmatically manage your social media content, including scheduling posts, uploading media, and retrieving information about your connected social accounts.

The base URL for all API requests is:

https://api.postfa.st/

We apply rate limits to prevent abuse and ensure fair usage. We do not allow spamming or unfair use of the API. You can review thefair usage policy. We reserve the right to terminate any API keys or accounts that violate our fair use policies or terms of service.

Rate Limiting

All API endpoints are subject to both global rate limits and endpoint-specific limits. Rate limits are tracked per API key, meaning each workspace has its own separate rate limit allowances.

The most restrictive limit applies first - if any rate limit is exceeded, the request will be rejected with a 429 status code.

Global Rate Limits (All Endpoints)

  • 60 requests per minute
  • 150 requests per 5 minutes
  • 300 requests per hour
  • 1000 requests per day

Rate Limit Headers

API responses include relevant rate limit headers for active throttlers:

X-RateLimit-Limit-short: 60
X-RateLimit-Remaining-short: 59
X-RateLimit-Reset-short: 60
X-RateLimit-Limit-medium: 150
X-RateLimit-Remaining-medium: 149
X-RateLimit-Reset-medium: 300
Retry-After-long: 2395

Header meanings:

  • X-RateLimit-Limit-[throttler]: Maximum requests allowed
  • X-RateLimit-Remaining-[throttler]: Requests remaining in window
  • X-RateLimit-Reset-[throttler]: Seconds until window resets
  • Retry-After-[throttler]: Seconds to wait before retry (when limited)

Rate Limit Exceeded (429 Response)

When rate limits are exceeded, you'll receive:

{
  "statusCode": 429,
  "message": "ThrottlerException: Too Many Requests"
}

Note: Headers vary by endpoint and show only active throttlers. Different endpoints may display different header combinations based on their specific rate limits.

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

II. API Endpoints

A. File Management

POST /file/get-signed-upload-urls

Generates pre-signed URLs for uploading media files (images or videos) directly to S3.

Rate Limit 150 requests per day.

File Size Limit Maximum 100 MB per file.

Request Headers:
  • pf-api-key: string (Required) - Your workspace API key.
Request Body (application/json):
  • contentType: string (Required) - The MIME type of the file.
    • Supported image types: image/jpeg, image/png, image/gif, image/webp.
    • Supported video types: video/mp4, video/webm, video/mov, video/quicktime.
  • count: number (Required) - Number of signed URLs.
    • Min: 1.
    • Max: 4 for images.
    • Max: 1 for videos (must be 1 if contentType is video).
Successful Response (200 OK):

An array of objects, each containing:

  • key: string - The S3 object key for upload.
  • signedUrl: string - The pre-signed S3 URL for PUT request.

Important Note for Uploading to S3:

After obtaining the signedUrl and key, perform an HTTP PUT request to the signedUrl with the raw file data as the request body. The Content-Type header in this PUT request must match the contentType used to generate the signed URL.

Example Request:
const response = await fetch('https://api.postfa.st/file/get-signed-upload-urls', {
  method: 'POST',
  headers: {
    'pf-api-key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    contentType: 'image/png',
    count: 2
  })
});

const data = await response.json();
Example Response (JSON):
[
  {
    "key": "image/a1b2c3d4-e5f6-7890-1234-567890abcdef.png",
    "signedUrl": "https://s3.amazonaws.com/postfast-uploads/image/a1b2c3d4-e5f6-7890-1234-567890abcdef.png?AWSAccessKeyId=AKIAEXAMPLE&Expires=1640995200&Signature=..."
  },
  {
    "key": "image/b2c3d4e5-f6a7-8901-2345-67890abcdef1.png",
    "signedUrl": "https://s3.amazonaws.com/postfast-uploads/image/b2c3d4e5-f6a7-8901-2345-67890abcdef1.png?AWSAccessKeyId=AKIAEXAMPLE&Expires=1640995200&Signature=..."
  }
]

B. 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.

Social media account IDs are immutable and can be safely cached in your application's storage (e.g., Redis, constants) to optimize performance and reduce API calls.

Rate Limit 90 requests per hour.

Request Headers:
  • pf-api-key: string (Required) - Your workspace API key.
Successful Response (200 OK):

An array of objects, each representing a social media account:

  • id: string - Unique identifier for the account.
  • platform: string - E.g., "X", "FACEBOOK", "INSTAGRAM", "THREADS", "LINKEDIN", "TIKTOK", "YOUTUBE", "BLUESKY".
  • platformUsername: string (Optional) - Username on the platform.
  • displayName: string (Optional) - Display name.
Example Request:
const response = await fetch('https://api.postfa.st/social-media/my-social-accounts', {
  method: 'GET',
  headers: {
    'pf-api-key': 'YOUR_API_KEY'
  }
});

const accounts = await response.json();
Example Response (JSON):
[
  {
    "id": "f1a2b3c4-d5e6-7890-1234-567890abcdef",
    "platform": "X",
    "platformUsername": "postfast_app",
    "displayName": "PostFast Official"
  },
  {
    "id": "a2b3c4d5-e6f7-8901-2345-67890abcdef1",
    "platform": "FACEBOOK",
    "platformUsername": null,
    "displayName": "My FB Page"
  }
]

C. Social Post Management

POST /social-posts

Creates and schedules one or more social posts.

Rate Limit 75 requests per day.

Platform Rate LimitsX (Twitter) posts through the API per account per day: 5, and we highly recommend not to exceed it on a daily basis.

Request Headers:
  • pf-api-key: string (Required)
Request Body (application/json):
  • posts: array (Required) - Array of post objects:
    • content: string (Required) - Text content.
    • mediaItems: array (Optional) - Array of media item objects:
      • key: string (Required) - S3 object key from /file/get-signed-upload-urls.
      • type: string (Required) - 'IMAGE' or 'VIDEO'.
      • sortOrder: number (Required) - Sort order for the media items.
      • coverTimestamp: string (Optional) - Timestamp in seconds to use as the cover image, if social media platform supports it.
    • scheduledAt: string (Optional for draft posts, otherwise required) - ISO 8601 date-time (e.g., YYYY-MM-DDTHH:mm:ss.sssZ). UTC.
    • socialMediaId: string (Required) - ID from /social-media/my-social-accounts.
  • status: string (Optional) - DRAFT or SCHEDULED. (default: SCHEDULED)
  • approvalStatus: string (Optional) - APPROVED or PENDING_APPROVAL. (default: APPROVED)
  • controls: object (Optional) - Platform-specific controls with sensible defaults:
    • X (Twitter) Controls:
      • xCommunityId: string (Optional) - Community ID for X posts
    • Instagram Controls:
      • instagramPublishType: string (Optional) - "TIMELINE" or "STORY" (default: "TIMELINE")
      • instagramPostToGrid: boolean (Optional) - Post to profile grid (default: true)
      • instagramCollaborators: string[] (Optional) - Array of Instagram usernames for collaboration (default: [])
    • Facebook Controls:
      • facebookContentType: string (Optional) - "POST", "REEL", or "STORY" (default: "POST")
        • POST: Up to 10 photos or 1 video (not mixed)
        • REEL: 1 video only
        • STORY: 1 image or 1 video
      • facebookReelsCollaborators: string[] (Optional) - Array of Facebook usernames for Reel collaboration (default: [])
    • TikTok Controls:
      • tiktokPrivacy: string (Optional) - "PUBLIC", "MUTUAL_FRIENDS", "ONLY_ME" (default: "PUBLIC")
      • tiktokIsDraft: boolean (Optional) - Save as draft (default: false)
      • tiktokAllowComments: boolean (Optional) - Allow comments (default: true)
      • tiktokAllowDuet: boolean (Optional) - Allow duets (default: true)
      • tiktokAllowStitch: boolean (Optional) - Allow stitches (default: true)
      • tiktokBrandOrganic: boolean (Optional) - Brand organic content (default: false)
      • tiktokBrandContent: boolean (Optional) - Branded content (default: false)
      • tiktokAutoAddMusic: boolean (Optional) - Auto-add music (default: false)
    • YouTube Controls:
      • youtubePrivacy: string (Optional) - "PRIVATE", "PUBLIC", "UNLISTED" (default: "PUBLIC")
      • youtubeTags: string[] (Optional) - Array of tags for the video (default: [])
      • youtubeCategoryId: string (Optional) - YouTube category ID (default: null)
      • youtubeIsShort: boolean (Optional) - Whether it's a YouTube Short (default: true)
      • youtubeMadeForKids: boolean (Optional) - COPPA compliance flag (default: false)
Successful Response (201 Created):

An object containing:

  • postIds: string[] - Array of unique IDs for the created posts.
Example Request:
TikTok Video
Facebook Post
Facebook Reel
Facebook Story
Instagram Timeline
Instagram Story
TikTok Carousel
TikTok Draft
YouTube Shorts
const response = await fetch('https://api.postfa.st/social-posts', {
  method: 'POST',
  headers: {
    'pf-api-key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    posts: [
      {
        content: "Amazing video content! 🎥 #trending #viral",
        mediaItems: [
          {
            key: "video/a7b8c9d1-e2f3-4567-8901-23456789abcd.mp4",
            type: "VIDEO",
            sortOrder: 0,
            coverTimestamp: "3"
          }
        ],
        scheduledAt: "2025-01-31T10:00:00.000Z",
        socialMediaId: "550e8400-e29b-41d4-a716-446655440001"
      }
    ],
    controls: {
      tiktokPrivacy: "PUBLIC",
      tiktokAllowComments: true,
      tiktokAllowDuet: true
    }
  })
});

const data = await response.json();
Example Response (JSON):
{
  "postIds": ["8d9e0f1a-2b3c-4567-8901-def123456789", "9e0f1a2b-3c4d-5678-9012-ef1234567890"]
}

DELETE /social-posts/{id}

Deletes a scheduled or failed social post.

Rate Limit 160 requests per hour.

Request Headers:
  • pf-api-key: string (Required)
Path Parameters:
  • id: string (Required) - The ID of the social post to delete.
Successful Response (200 OK):

A JSON object indicating success:

{
  "deleted": true 
}

(Returns { "deleted": false } or an error if deletion fails or post not found).

Example Request:
const response = await fetch('https://api.postfa.st/social-posts/8d9e0f1a-2b3c-4567-8901-def123456789', {
  method: 'DELETE',
  headers: {
    'pf-api-key': 'YOUR_API_KEY'
  }
});

const result = await response.json();
Example Response (JSON):
{
  "deleted": true
}

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.
  • 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 (e.g., a specific social post for deletion) could not be found.
  • 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.