Install
openclaw skills install adaptlypostSchedule and manage social media posts across Instagram, X (Twitter), Bluesky, TikTok, Threads, LinkedIn, Facebook, Pinterest, and YouTube using the AdaptlyPost 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 post status, cross-post content to multiple platforms, or automate their social media workflow. AdaptlyPost is a SaaS tool — no self-hosting required.
openclaw skills install adaptlypostSchedule social media posts across 9 platforms from one API. SaaS — no self-hosting needed.
export ADAPTLYPOST_API_KEY="adaptly_your-token-here"
Base URL: https://post.adaptlypost.com/post/api/v1
Auth header: Authorization: Bearer $ADAPTLYPOST_API_KEY
Posts are public, attributable, and hard to fully retract. Treat every POST /social-posts and POST /upload-urls as a high-impact action.
POST /social-posts, show the user a summary and get an explicit "yes" covering all four items:
displayName/username, not just ID)privacyLevel, YouTube privacyStatus, Instagram postType, etc.
A previous "yes" does not authorize a new post. Re-confirm each one.saveAsDraft: true and let them review in the AdaptlyPost UI before publishing./upload-urls are stored at a public URL that exists from the moment of upload — before the post goes live, and even if the post is never created. Before calling /upload-urls:
~/Downloads, ~/Desktop, screenshot folders, etc.) without an explicit per-file "yes".POST /social-posts returns an error or unexpected skippedPlatforms, surface it to the user and ask before retrying — do not loop.curl -s -H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
https://post.adaptlypost.com/post/api/v1/social-accounts
Returns { "accounts": [{ "id", "platform", "displayName", "username", "avatarUrl" }] }. Save the id — you'll use it as a connection ID when creating posts.
⚠️ Immediate publish is irreversible from the agent's side — once POST /social-posts returns, the content is live on the user's connected accounts. Only call this after the four-item confirmation in Safety rules.
To publish right away, simply omit scheduledAt entirely and do NOT set saveAsDraft:
curl -X POST https://post.adaptlypost.com/post/api/v1/social-posts \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["TWITTER"],
"contentType": "TEXT",
"text": "This goes live right now!",
"timezone": "America/New_York",
"twitterConnectionIds": ["CONNECTION_ID_HERE"]
}'
IMPORTANT: Do NOT set scheduledAt to a time in the near future as a workaround. Omitting scheduledAt is the correct way to publish immediately.
Returns { "postId", "queuedPlatforms", "skippedPlatforms", "isScheduled", "scheduledAt" }.
Important: You must include the correct *ConnectionIds array for each platform in platforms. For example, if posting to Instagram and Twitter, include both instagramConnectionIds and twitterConnectionIds. For Facebook, use pageIds instead.
curl -X POST https://post.adaptlypost.com/post/api/v1/social-posts \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["TWITTER"],
"contentType": "TEXT",
"text": "Your post text here",
"timezone": "America/New_York",
"scheduledAt": "2026-06-15T10:00:00.000Z",
"twitterConnectionIds": ["CONNECTION_ID_HERE"]
}'
Same as scheduling, but set saveAsDraft: true and omit scheduledAt:
curl -X POST https://post.adaptlypost.com/post/api/v1/social-posts \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["INSTAGRAM"],
"contentType": "TEXT",
"text": "Draft post to review later",
"timezone": "Europe/London",
"saveAsDraft": true,
"instagramConnectionIds": ["CONNECTION_ID_HERE"]
}'
⚠️ The publicUrl returned in Step A is publicly reachable as soon as Step B completes — even if you never create the post in Step C. Confirm the exact file path with the user before Step A, and never upload a file the user has not explicitly named.
Step A — Get presigned upload URLs:
curl -X POST https://post.adaptlypost.com/post/api/v1/upload-urls \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "files": [{ "fileName": "photo.jpg", "mimeType": "image/jpeg" }] }'
Returns { "urls": [{ "fileName", "uploadUrl", "publicUrl", "key", "expiresAt" }] }.
Step B — Upload file to storage:
curl -X PUT "UPLOAD_URL_HERE" \
-H "Content-Type: image/jpeg" \
--data-binary @/path/to/photo.jpg
Step C — Create post with the public URL:
curl -X POST https://post.adaptlypost.com/post/api/v1/social-posts \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["INSTAGRAM"],
"contentType": "IMAGE",
"text": "Post with image!",
"mediaUrls": ["PUBLIC_URL_FROM_STEP_A"],
"timezone": "America/New_York",
"scheduledAt": "2026-06-15T10:00:00.000Z",
"instagramConnectionIds": ["CONNECTION_ID_HERE"]
}'
For video: use mimeType: "video/mp4", contentType: "VIDEO".
For carousel: upload multiple files, include all public URLs in mediaUrls, use contentType: "CAROUSEL".
curl -s -H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
"https://post.adaptlypost.com/post/api/v1/social-posts?limit=20&offset=0"
Returns { "posts": [...], "total": 25, "hasMore": true }. Use limit (1-100, default 20) and offset (default 0) for pagination.
curl -s -H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
https://post.adaptlypost.com/post/api/v1/social-posts/POST_ID
Returns full post object with platform-specific status for each target platform.
Include multiple platforms and their connection IDs in a single request:
curl -X POST https://post.adaptlypost.com/post/api/v1/social-posts \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["TWITTER", "BLUESKY", "LINKEDIN"],
"contentType": "TEXT",
"text": "Same post across 3 platforms!",
"timezone": "America/New_York",
"scheduledAt": "2026-06-15T10:00:00.000Z",
"twitterConnectionIds": ["TWITTER_ID"],
"blueskyConnectionIds": ["BLUESKY_ID"],
"linkedinConnectionIds": ["LINKEDIN_ID"]
}'
Override the default text for specific platforms:
curl -X POST https://post.adaptlypost.com/post/api/v1/social-posts \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["TWITTER", "LINKEDIN"],
"contentType": "TEXT",
"text": "Default text for all platforms",
"platformTexts": [
{ "platform": "TWITTER", "text": "Short version for X #shortform" },
{ "platform": "LINKEDIN", "text": "Longer professional version with more detail for LinkedIn audience." }
],
"timezone": "America/New_York",
"scheduledAt": "2026-06-15T10:00:00.000Z",
"twitterConnectionIds": ["TWITTER_ID"],
"linkedinConnectionIds": ["LINKEDIN_ID"]
}'
Pass these as config arrays in the request body. See references/platform-configs.md for full details.
| Platform | Config Field | Key Options |
|---|---|---|
| TikTok | tiktokConfigs | privacyLevel (required), allowComments, allowDuet, allowStitch, sendAsDraft, brandedContent, autoAddMusic |
instagramConfigs | postType (FEED/REEL/STORY) | |
facebookConfigs | postType (FEED/REEL/STORY), videoTitle | |
| YouTube | youtubeConfigs | postType (VIDEO/SHORTS), videoTitle, tags, privacyStatus, madeForKids, playlistId |
pinterestConfigs | boardId (required), title, link | |
| X (Twitter) | — | No config object, uses twitterConnectionIds only |
| Bluesky | — | No config object, uses blueskyConnectionIds only |
| Threads | — | No config object, uses threadsConnectionIds only |
| — | No config object, uses linkedinConnectionIds only |
Example with TikTok config:
curl -X POST https://post.adaptlypost.com/post/api/v1/social-posts \
-H "Authorization: Bearer $ADAPTLYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["TIKTOK"],
"contentType": "VIDEO",
"text": "Check out this clip!",
"mediaUrls": ["https://cdn.adaptlypost.com/social-media-posts/uuid/video.mp4"],
"timezone": "America/New_York",
"scheduledAt": "2026-06-15T18:00:00.000Z",
"tiktokConnectionIds": ["TIKTOK_ID"],
"tiktokConfigs": [{
"connectionId": "TIKTOK_ID",
"privacyLevel": "PUBLIC_TO_EVERYONE",
"allowComments": true,
"allowDuet": false,
"allowStitch": true
}]
}'
| MIME Type | Extension | Use For |
|---|---|---|
image/jpeg | .jpg, .jpeg | Images |
image/png | .png | Images |
image/webp | .webp | Images |
video/mp4 | .mp4 | Videos |
video/quicktime | .mov | Videos |
Upload 1-20 files per request.
| Platform | Images | Video | Carousel |
|---|---|---|---|
| TikTok | Carousels only | MP4/MOV, ≤250MB, 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 | |
| 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 |
POST /social-posts, show a final summary covering content, platforms (named, not just IDs), timing, and visibility, and wait for an explicit "yes". Re-confirm for every post — prior approval does not carry over.saveAsDraft: true so the user can review in the AdaptlyPost UI before anything goes live.scheduledAt from the request body — do NOT set it to a time in the near future. The API publishes immediately when scheduledAt is absent.scheduledAt to an ISO 8601 timestamp.saveAsDraft: true and omit scheduledAt.timezone field is required on every post creation request.Europe/London, Europe/Berlin, Europe/Paris, America/New_York, America/Chicago, America/Los_Angeles, Asia/Tokyo, Australia/Sydney./social-accounts first to get valid connection IDs for each platform.mediaUrls).scheduledAt must be ISO 8601 and in the future. Omit it when using saveAsDraft: true.twitterConnectionIds, instagramConnectionIds, blueskyConnectionIds, linkedinConnectionIds, tiktokConnectionIds, threadsConnectionIds, pinterestConnectionIds, youtubeConnectionIds. Facebook uses pageIds.privacyLevel — always set it (e.g., PUBLIC_TO_EVERYONE).boardId — there is no way to fetch boards via this API currently, so ask the user which board to use.mediaUrls.platformTexts to customize text per platform when cross-posting.TEXT (no media), IMAGE (single image), VIDEO (single video), CAROUSEL (multiple images/videos).skippedPlatforms in the response — it tells you if any platform was skipped and why.