executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
postfastSchedule and manage social media posts across TikTok, Instagram, Facebook, X (Twitter), YouTube, LinkedIn, Threads, Bluesky, Pinterest, and Telegram using the PostFast API. Use when the user wants to schedule social media posts, manage social media content, upload media for social posting, list connected social accounts, check scheduled posts, delete schedu…
Independent GitHub snapshot · Automated classification · Original documentation governs
Schedule social media posts across 10 platforms from one API. SaaS — no self-hosting needed.
export POSTFAST_API_KEY="your-api-key"
Base URL: https://api.postfa.st
Auth header: pf-api-key: $POSTFAST_API_KEY
curl -s -H "pf-api-key: $POSTFAST_API_KEY" https://api.postfa.st/social-media/my-social-accounts
Returns array of { id, platform, platformUsername, displayName }. Save the id — it's the socialMediaId required for every post.
Platform values: TIKTOK, INSTAGRAM, FACEBOOK, X, YOUTUBE, LINKEDIN, THREADS, BLUESKY, PINTEREST, TELEGRAM
curl -X POST https://api.postfa.st/social-posts \
-H "pf-api-key: $POSTFAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"posts": [{
"content": "Your post text here",
"mediaItems": [],
"scheduledAt": "2026-06-15T10:00:00.000Z",
"socialMediaId": "ACCOUNT_ID_HERE"
}],
"controls": {}
}'
Returns { "postIds": ["uuid-1"] }.
Step A — Get signed upload URLs:
curl -X POST https://api.postfa.st/file/get-signed-upload-urls \
-H "pf-api-key: $POSTFAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "contentType": "image/png", "count": 1 }'
Returns [{ "key": "image/uuid.png", "signedUrl": "https://..." }].
Step B — Upload file to S3:
curl -X PUT "SIGNED_URL_HERE" \
-H "Content-Type: image/png" \
--data-binary @/path/to/file.png
Step C — Create post with media key:
curl -X POST https://api.postfa.st/social-posts \
-H "pf-api-key: $POSTFAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"posts": [{
"content": "Post with image!",
"mediaItems": [{ "key": "image/uuid.png", "type": "IMAGE", "sortOrder": 0 }],
"scheduledAt": "2026-06-15T10:00:00.000Z",
"socialMediaId": "ACCOUNT_ID_HERE"
}],
"controls": {}
}'
For video: use contentType: "video/mp4", type: "VIDEO", key prefix video/.
curl -s -H "pf-api-key: $POSTFAST_API_KEY" "https://api.postfa.st/social-posts?page=0&limit=20"
Returns { "data": [...], "totalCount": 25, "pageInfo": { "page": 1, "hasNextPage": true, "perPage": 20 } }.
Query parameters:
page (int, default 0) — 0-based page index. Response shows 1-based display page in pageInfo.pagelimit (int, default 20, max 50) — items per pageplatforms (string) — comma-separated filter: FACEBOOK,INSTAGRAM,Xstatuses (string) — comma-separated: DRAFT, SCHEDULED, PUBLISHED, FAILEDfrom / to (ISO 8601 UTC) — date range filter on scheduledAtExample: GET /social-posts?page=0&limit=50&platforms=X,LINKEDIN&statuses=SCHEDULED&from=2026-06-01T00:00:00Z&to=2026-06-30T23:59:59Z
curl -X DELETE -H "pf-api-key: $POSTFAST_API_KEY" https://api.postfa.st/social-posts/POST_ID
Include multiple entries in the posts array, each with a different socialMediaId. They share the same controls and mediaItems keys.
Let clients connect their social accounts to your workspace without creating a PostFast account:
curl -X POST https://api.postfa.st/social-media/connect-link \
-H "pf-api-key: $POSTFAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "expiryDays": 7, "sendEmail": true, "email": "client@example.com" }'
Returns { "connectUrl": "https://app.postfa.st/connect?token=..." }. Share the URL — they can connect accounts directly. Rate limit: 50/hour.
Omit scheduledAt and set status: "DRAFT" to save without scheduling:
curl -X POST https://api.postfa.st/social-posts \
-H "pf-api-key: $POSTFAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"posts": [{ "content": "Draft idea...", "mediaItems": [], "socialMediaId": "ACCOUNT_ID" }],
"status": "DRAFT",
"controls": {}
}'
Fetch published posts with their performance metrics:
curl -s -H "pf-api-key: $POSTFAST_API_KEY" \
"https://api.postfa.st/social-posts/analytics?startDate=2026-03-01T00:00:00.000Z&endDate=2026-03-31T23:59:59.999Z&platforms=TIKTOK,INSTAGRAM"
Query parameters:
startDate (ISO 8601, required) — start of date rangeendDate (ISO 8601, required) — end of date rangeplatforms (string, optional) — comma-separated filtersocialMediaIds (string, optional) — comma-separated account UUIDsReturns { "data": [{ id, content, socialMediaId, platformPostId, publishedAt, latestMetric }] }.
latestMetric fields: impressions, reach, likes, comments, shares, totalInteractions, fetchedAt, extras. All numbers are strings (bigint). latestMetric is null if metrics haven't been fetched yet. LinkedIn personal accounts are excluded.
Rate limit: 350/hour.
Post the same content to LinkedIn, X, and Threads at the same time:
curl -X POST https://api.postfa.st/social-posts \
-H "pf-api-key: $POSTFAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"posts": [
{ "content": "Big announcement!", "mediaItems": [], "scheduledAt": "2026-06-15T09:00:00.000Z", "socialMediaId": "LINKEDIN_ID" },
{ "content": "Big announcement!", "mediaItems": [], "scheduledAt": "2026-06-15T09:00:00.000Z", "socialMediaId": "X_ID" },
{ "content": "Big announcement!", "mediaItems": [], "scheduledAt": "2026-06-15T09:00:00.000Z", "socialMediaId": "THREADS_ID" }
],
"controls": {}
}'
See examples/cross-platform-post.json for a complete example.
contentType: "video/mp4"instagramPublishType: "REEL"See examples/instagram-reel.json for the request body.
Upload video, then post with privacy controls:
# controls object:
{
"tiktokPrivacy": "PUBLIC",
"tiktokAllowComments": true,
"tiktokAllowDuet": false,
"tiktokAllowStitch": false,
"tiktokBrandContent": true
}
See examples/tiktok-video.json.
Always fetch boards first, then post:
# Step 1: Get boards
curl -s -H "pf-api-key: $POSTFAST_API_KEY" \
https://api.postfa.st/social-media/PINTEREST_ACCOUNT_ID/pinterest-boards
# Step 2: Post with board ID
# controls: { "pinterestBoardId": "BOARD_ID", "pinterestLink": "https://yoursite.com" }
See examples/pinterest-pin.json.
Upload video, then post with YouTube controls:
# controls object:
{
"youtubeIsShort": true,
"youtubeTitle": "Quick Tip: Batch Your Content",
"youtubePrivacy": "PUBLIC",
"youtubePlaylistId": "PLxxxxxx",
"youtubeTags": ["tips", "productivity", "social media"],
"youtubeMadeForKids": false
}
See examples/youtube-short.json.
Documents (PDF, PPTX, DOCX) display as swipeable carousels on LinkedIn.
contentType: "application/pdf"linkedinAttachmentKey instead of mediaItems# controls: { "linkedinAttachmentKey": "file/uuid.pdf", "linkedinAttachmentTitle": "Q1 Marketing Playbook" }
# Note: mediaItems should be [] when using linkedinAttachmentKey
See examples/linkedin-document.json.
Add a firstComment to any post — it's auto-posted ~10 seconds after the main post goes live (up to 3 retries):
{
"posts": [{ "content": "Main post text", "firstComment": "Link: https://postfa.st", "mediaItems": [], "scheduledAt": "...", "socialMediaId": "X_ID" }],
"controls": {}
}
Supported on: X, Instagram, Facebook, YouTube, Threads. NOT supported on: TikTok, Pinterest, Bluesky, LinkedIn.
See examples/x-first-comment.json.
Schedule a retweet — content and media are ignored:
{
"posts": [{ "content": "", "scheduledAt": "...", "socialMediaId": "X_ID" }],
"controls": { "xRetweetUrl": "https://x.com/username/status/1234567890" }
}
See examples/x-retweet.json. For quote tweets with your own commentary, use xQuoteTweetUrl instead. See examples/x-quote-tweet.json.
Schedule multiple posts at different times in a single API call (up to 15 posts per request):
See examples/batch-scheduling.json.
Pass these in the controls object. See references/platform-controls.md for full details.
| Platform | Key Controls |
|---|---|
| TikTok | tiktokPrivacy, tiktokAllowComments, tiktokAllowDuet, tiktokAllowStitch, tiktokIsDraft, tiktokBrandOrganic, tiktokBrandContent, tiktokAutoAddMusic |
instagramPublishType (TIMELINE/STORY/REEL), instagramPostToGrid, instagramCollaborators | |
facebookContentType (POST/REEL/STORY), facebookReelsCollaborators | |
| YouTube | youtubeIsShort, youtubeTitle, youtubePrivacy, youtubePlaylistId, youtubeTags, youtubeMadeForKids, youtubeCategoryId |
linkedinAttachmentKey, linkedinAttachmentTitle (for document posts) | |
| X (Twitter) | xQuoteTweetUrl (quote tweet), xRetweetUrl (retweet), xCommunityId (post to community) |
pinterestBoardId (required), pinterestLink | |
| Bluesky | No platform-specific controls — text + images only |
| Threads | No platform-specific controls — text + images/video |
| Telegram | No platform-specific controls — text + images/video/mixed media |
GET /social-media/{id}/pinterest-boards → returns [{ boardId, name }]GET /social-media/{id}/youtube-playlists → returns [{ playlistId, title }]POST /social-media/connect-link → returns { connectUrl }. Let clients connect accounts without a PostFast account. Params: expiryDays (1-30, default 7), sendEmail (bool), email (required if sendEmail=true)Global (per API key): 60/min, 150/5min, 300/hour, 2000/day
Per-endpoint:
POST /social-posts: 350/dayGET /social-posts: 200/hourGET /social-posts/analytics: 350/hourPOST /social-media/connect-link: 50/hourPlatform limits:
Check X-RateLimit-Remaining-* headers. 429 = rate limited, check Retry-After-* header. For batch operations, add a 1-second delay between API calls.
| Platform | Images | Video | Carousel |
|---|---|---|---|
| TikTok | Carousels only | ≤250MB, MP4/MOV, 3s-10min | 2-35 images |
| JPEG/PNG | ≤1GB, 3-90s (Reels) | Up to 10 | |
| ≤30MB, JPG/PNG | 1 per post | Up to 10 images | |
| YouTube | — | Shorts ≤3min, H.264 | — |
| Up to 9 | ≤10min | Up to 9, or documents (PDF/PPTX/DOCX) | |
| X (Twitter) | Up to 4 | — | — |
| 2:3 ratio ideal | Supported | 2-5 images | |
| Bluesky | Up to 4 | Not supported | — |
| Threads | Supported | Supported | Up to 10 |
| Telegram | Up to 10 | Supported | Up to 10 mixed media |
socialMediaId is a UUID, not a platform name. Call GET /social-media/my-social-accounts to get valid IDs.key in mediaItems.scheduledAt must be in the future — ISO 8601 UTC format. Past dates return 400.pinterestBoardId — Fetch boards first with GET /social-media/{id}/pinterest-boards.linkedinAttachmentKey — NOT mediaItems. Set mediaItems: [] when posting documents.Content-Type header in your S3 PUT must match what you requested in get-signed-upload-urls.controls object applies to ALL posts in the batch. Platform-irrelevant controls are ignored.firstComment only works on 5 platforms — X, Instagram, Facebook, YouTube, Threads. TikTok, Pinterest, Bluesky, LinkedIn return a validation error.xQuoteTweetUrl and xRetweetUrl together — Pick one. Retweets ignore content/media.page=0 returns the first page. Response pageInfo.page shows 1-based display number.Reference docs:
Ready-to-use examples:
# Auth
Header: pf-api-key: $POSTFAST_API_KEY
# List accounts
GET /social-media/my-social-accounts
# Schedule post
POST /social-posts { posts: [{ content, mediaItems, scheduledAt, socialMediaId, firstComment? }], status?, approvalStatus?, controls: {} }
# Draft post (no scheduledAt needed)
POST /social-posts { posts: [...], status: "DRAFT", controls: {} }
# List posts (page is 0-based, limit max 50)
GET /social-posts?page=0&limit=20
GET /social-posts?page=0&limit=50&platforms=X,LINKEDIN&statuses=SCHEDULED&from=2026-06-01T00:00:00Z&to=2026-06-30T23:59:59Z
# Delete post
DELETE /social-posts/:id
# Upload media (3 steps)
POST /file/get-signed-upload-urls { contentType, count }
PUT <signedUrl> (raw file, matching Content-Type)
# then use key in mediaItems
# Pinterest boards
GET /social-media/:id/pinterest-boards
# YouTube playlists
GET /social-media/:id/youtube-playlists
# Post analytics (published posts with metrics)
GET /social-posts/analytics?startDate=...&endDate=...&platforms=...
# Connect link (for clients)
POST /social-media/connect-link { expiryDays?, sendEmail?, email? }
my-social-accounts first to get valid socialMediaId values.scheduledAt must be ISO 8601 UTC and in the future.pinterestBoardId — fetch boards first.linkedinAttachmentKey instead of mediaItems.mediaItems with sequential sortOrder.coverTimestamp (seconds) in mediaItems.firstComment for CTAs and links — keeps the main post clean and gets better engagement.status: "DRAFT" and omit scheduledAt — the user can finalize in the PostFast dashboard.GET /social-posts with from/to filters to check what's already scheduled before adding more.