SDKs & CLI
PostEverywhere provides a Node.js SDK, a CLI, and REST API access for any language. Pick the approach that fits your workflow.
Node.js SDK
Installation
npm install @posteverywhere/sdk
Initialization
import { PostEverywhere } from '@posteverywhere/sdk';
const client = new PostEverywhere({
apiKey: process.env.POSTEVERYWHERE_API_KEY, // pe_live_...
});
Never hard-code your API key. Use environment variables or a secrets manager. See Authentication for details.
List Connected Accounts
const { accounts } = await client.accounts.list();
for (const account of accounts) {
console.log(`${account.platform} — @${account.username} (${account.status})`);
}
Create and Schedule a Post
const post = await client.posts.create({
content: 'Just shipped a major update! Check it out at example.com',
account_ids: [123, 456],
scheduled_for: '2026-04-07T14:00:00Z', // canonical — always UTC
});
console.log(`Post ${post.id} scheduled for ${post.scheduled_for}`);
The response from client.posts.create() has the same top-level field names as the request, so you can take any post and create a clone by passing its fields straight back in. scheduled_for, account_ids, media_ids, platform_content, timezone, content — all round-trip.
Save a Draft, Then Schedule It
Pass draft: true to save a post without publishing or scheduling it (account_ids is optional for a draft). Review it later, then schedule it with POST /v1/posts/{id}/schedule — sending either scheduled_for or publish_now: true. The schedule endpoint only works on drafts.
// 1. Save a draft (nothing publishes yet)
const draft = await client.posts.create({
content: 'Proposed announcement — review before sending.',
draft: true,
// account_ids optional for drafts
});
// 2. ...review it (e.g. client.posts.list({ status: 'draft' }))...
// 3. Schedule (or publish now) the approved draft
await fetch(
`https://app.posteverywhere.ai/api/v1/posts/${draft.post_id}/schedule`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.POSTEVERYWHERE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
scheduled_for: '2026-04-15T14:30:00Z', // OR: publish_now: true
account_ids: [123, 456], // optional if the draft already had targets
}),
},
);
This "draft → review → schedule" flow is the recommended human-in-the-loop pattern for AI agents — see Building AI Agents.
Platform-Specific Content
Customize content per platform using platform_content:
const post = await client.posts.create({
content: 'Default content for all platforms',
account_ids: [123, 456, 789],
platform_content: {
x: {
content: 'Short version for X (under 280 chars)',
},
linkedin: {
content: 'Longer, more detailed version for LinkedIn with professional tone...',
},
instagram: {
content: 'Visual-first caption with #hashtags',
},
},
scheduled_for: '2026-04-07T14:00:00Z',
});
Upload Media
import fs from 'fs';
// Start an upload
const upload = await client.media.upload({
fileName: 'product-launch.jpg',
contentType: 'image/jpeg',
});
// Upload the file to the pre-signed URL
await fetch(upload.uploadUrl, {
method: 'PUT',
body: fs.readFileSync('./product-launch.jpg'),
headers: { 'Content-Type': 'image/jpeg' },
});
// Complete the upload
const media = await client.media.complete(upload.mediaId);
// Use it in a post
await client.posts.create({
content: 'Our new product is here!',
account_ids: [123],
media_ids: [media.id],
});
Schedule a Week of Posts
Loop through your posts and call create() for each with a future scheduled_for:
const posts = [
{ content: 'Monday motivation: ship fast, learn faster', scheduled_for: '2026-04-07T09:00:00Z' },
{ content: 'Tuesday tip: automate your social media with APIs', scheduled_for: '2026-04-08T09:00:00Z' },
{ content: 'Wednesday win: our users scheduled 10,000 posts last week', scheduled_for: '2026-04-09T09:00:00Z' },
{ content: 'Thursday thought: the best content strategy is consistency', scheduled_for: '2026-04-10T09:00:00Z' },
{ content: 'Friday launch: new API endpoints are live!', scheduled_for: '2026-04-11T09:00:00Z' },
];
const results = await Promise.allSettled(
posts.map((p) =>
client.posts.create({
content: p.content,
account_ids: [123, 456],
scheduled_for: p.scheduled_for,
})
)
);
const created = results.filter((r) => r.status === 'fulfilled').length;
const failed = results.filter((r) => r.status === 'rejected').length;
console.log(`Scheduled ${created} posts, ${failed} failed`);
Check Post Results
const results = await client.posts.getResults('post_789');
// `destinations` is a rich per-platform array with account_id, account_name,
// status, platform_post_url, error (if failed), and published_at.
for (const dest of results.destinations) {
console.log(`${dest.platform} (@${dest.account_name}): ${dest.status}`);
if (dest.status === 'failed' && dest.error) {
console.log(` [${dest.error.code}] ${dest.error.message}`);
} else if (dest.status === 'published') {
console.log(` ${dest.platform_post_url}`);
}
}
CLI
The @posteverywhere/cli package manages posts and accounts from your terminal — or from any AI agent that can run shell commands. Every command prints structured JSON to stdout (errors go to stderr with a non-zero exit), so it's easy to pipe into jq or parse programmatically. Nothing to install: run it with npx.
Authentication
The CLI reads your API key from an environment variable — there is no separate login step:
export POSTEVERYWHERE_API_KEY="pe_live_..." # Settings → Developers
Common commands
# Verify the key — shows the account, plan, and quota
npx @posteverywhere/cli whoami
# List connected accounts (you need the numeric `id`s to post)
npx @posteverywhere/cli accounts
# Publish now to accounts 123 and 456
npx @posteverywhere/cli post -c "Just shipped v2.0! 🚀" -a 123,456
# Schedule (ISO-8601, UTC) — add -s
npx @posteverywhere/cli post -c "Big announcement" -a 123,456 -s 2026-07-01T09:00:00Z
# Import an image by URL, then attach the returned media_id
npx @posteverywhere/cli upload https://example.com/banner.jpg # → { "media_id": "..." }
npx @posteverywhere/cli post -c "New drop" -a 123 -m <media_id>
# Inspect posts and per-platform results
npx @posteverywhere/cli posts --status published --limit 10
npx @posteverywhere/cli results <postId>
npx @posteverywhere/cli retry <postId> # retry failed platforms
# Why can't an account post? (needs reconnect, quota, etc.)
npx @posteverywhere/cli account:health <id>
# AI captions + analytics summary
npx @posteverywhere/cli caption -t "summer sale" --platform instagram --tone playful
npx @posteverywhere/cli analytics --period month
Run npx @posteverywhere/cli help for the full command list. Prefer a global install? npm i -g @posteverywhere/cli lets you drop the npx @posteverywhere/cli prefix and just call posteverywhere <command>.
CLI in CI/CD pipelines
Use the CLI in GitHub Actions or other CI to announce releases as part of your pipeline:
# .github/workflows/release.yml
- name: Announce release on social media
env:
POSTEVERYWHERE_API_KEY: ${{ secrets.POSTEVERYWHERE_API_KEY }}
run: |
npx @posteverywhere/cli post \
-c "v${{ github.event.release.tag_name }} is live! ${{ github.event.release.html_url }}" \
-a 123,456
Built for AI agents
The package ships a SKILL.md that teaches agents (Claude, Cursor, ChatGPT, OpenAI Codex, and others) the command surface for auto-discovery. If you'd rather connect over MCP than shell out, see the MCP Server guide — the hosted endpoint exposes the same capabilities with no install. (For ChatGPT, connect via the hosted connector on the agents page.)
Python
A dedicated Python SDK is not yet available. In the meantime, you can call the REST API directly with requests:
import requests
import os
API_KEY = os.environ["POSTEVERYWHERE_API_KEY"]
BASE_URL = "https://app.posteverywhere.ai/api/v1"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
# List accounts
accounts = requests.get(f"{BASE_URL}/accounts", headers=headers).json()
print(accounts["data"])
# Create a scheduled post
post = requests.post(
f"{BASE_URL}/posts",
headers=headers,
json={
"content": "Hello from Python!",
"account_ids": [123, 456],
"scheduled_for": "2026-04-07T14:00:00Z", # canonical — UTC
},
).json()
print(f"Post {post['data']['id']} scheduled for {post['data']['scheduled_for']}")
cURL
For quick one-off requests or shell scripts:
# List accounts
curl https://app.posteverywhere.ai/api/v1/accounts \
-H "Authorization: Bearer $POSTEVERYWHERE_API_KEY"
# Create a post
curl -X POST https://app.posteverywhere.ai/api/v1/posts \
-H "Authorization: Bearer $POSTEVERYWHERE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Hello from cURL!",
"account_ids": [123],
"scheduled_for": "2026-04-07T14:00:00Z"
}'
# Upload media — one-call from a public URL (preferred when source is online)
curl -X POST https://app.posteverywhere.ai/api/v1/media/upload-from-url \
-H "Authorization: Bearer $POSTEVERYWHERE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/hero.webp"}'
# Upload media — 3-step flow (for local files or videos)
# Step 1: Get presigned URL. Required fields: filename, content_type, size.
curl -X POST https://app.posteverywhere.ai/api/v1/media/upload \
-H "Authorization: Bearer $POSTEVERYWHERE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "photo.jpg", "content_type": "image/jpeg", "size": 2048576}'
# Step 2: PUT/POST the bytes to the returned upload_url
# Step 3: POST /api/v1/media/{media_id}/complete to finalise
Next Steps
- Quick Start — Make your first API call in 5 minutes
- Authentication — API key scopes and security
- MCP Server — Use PostEverywhere from Claude, Cursor, or Windsurf
- API Reference — Full endpoint documentation