How do I schedule a single post?
curl -X POST https://api.socifyr.com/api/content/text \
-H "Authorization: Bearer sk_your_key" \
-H "X-Workspace-Id: <workspaceId>" \
-H "Content-Type: application/json" \
-d '{
"connections": ["linkedin-mybrand", "x-myhandle"],
"text": "Webinar starts in one hour",
"scheduledAt": "2026-12-01T09:00:00Z"
}'The same field works on /content/photos, /content/video and /content/document, and in the SDK on any create call. In the CLI it is --at, and over MCP it is schedule_post.
socifyr post "Webinar starts in one hour" --to linkedin-mybrand --at 2026-12-01T09:00:00ZHow do time zones work with scheduledAt?
scheduledAt is always ISO 8601. Include a UTC offset to pin a wall-clock time: 2026-12-01T09:00:00-05:00 is 9am Eastern Standard Time. The optional timezone field takes an IANA name such as America/New_York and controls how the time displays in the dashboard. It does not change when the post publishes, so decide the instant with the offset or Z and treat timezone as presentation. Daylight saving changes are the usual trap: compute the UTC instant in your own code with a tz-aware library rather than hard-coding an offset for a date months away.
How do I schedule many posts at once?
POST /api/content/bulk-schedule takes either a rows array or a csv string with the header text,connections,scheduledAt,title. It accepts up to 500 rows and returns how many were created plus an error per failed row, so one bad row does not sink the batch. Bulk scheduling is for text posts.
const res = await socifyr.uploads.bulkSchedule({
rows: [
{ text: 'Monday: shipping update', connections: ['linkedin-mybrand'], scheduledAt: '2026-12-07T09:00:00Z' },
{ text: 'Wednesday: deep dive', connections: ['linkedin-mybrand'], scheduledAt: '2026-12-09T09:00:00Z' },
],
})
console.log(`${res.created} scheduled, ${res.failed.length} failed`)socifyr schedule posts.csvAn AI agent can do the same with the schedule_posts MCP tool, which takes 1 to 500 posts in a single call and is preferred over calling schedule_post in a loop.
How do I reschedule, cancel or publish a scheduled post now?
| Goal | SDK | CLI | MCP |
|---|---|---|---|
| Change the time or accounts | uploads.update(id, { scheduledAt }) | socifyr edit <id> --at <iso> | update_post |
| Publish now | uploads.publishNow(id) | n/a | n/a |
| Cancel | uploads.cancel(id) | n/a | n/a |
| List what is scheduled | uploads.list({ status: 'scheduled' }) | n/a | list_posts with status: scheduled |
A new scheduledAt must be in the future, and rescheduling re-syncs the queued job. Posts that are already published or in flight cannot be edited. In the lifecycle, scheduling is a field rather than a status: a scheduled post waits in queued or pending until its time, and there is no separate scheduled status.
Which plans can schedule, and what else can block a scheduled post?
| Plan | Scheduling | Uploads per month |
|---|---|---|
| Free | Not available | 30 |
| Pro ($9.99) | Yes | Unlimited |
| Business ($39) | Yes | Unlimited |
Three things can still stop a scheduled post once its time arrives. The platform's daily posting cap applies when it publishes. The account token must still be valid; Socifyr warns by email 7 days before expiry, and the reconnect link updates the connection in place, so scheduled posts keep working. And for X, the monthly allowance and any per-key spend cap are counted against a post when it is dispatched, scheduled posts included.
How do I run recurring posts?
Socifyr has no built-in cron or repeat rule. For "every Monday at 9am", run a scheduler in your own infrastructure (cron, GitHub Actions, a queue) that calls the API once per occurrence. That keeps the recurrence logic, and any content generation, in your hands. A common pattern is a weekly job that generates the next week of posts and submits them through bulk-schedule.
How do I confirm a scheduled post went out?
A scheduled post is a normal post with a future time. When the time arrives it moves through the same pipeline as an immediate post, so the status endpoints and webhooks work the same way. Look the post up by its ID or request ID after the scheduled time and read the per-channel results.
const status = await socifyr.uploads.getStatus(upload.id!)
for (const ch of status.channels) {
console.log(ch.platform, ch.result?.status, ch.result?.postUrl, ch.result?.error)
}For production use, prefer webhooks to polling. The upload.completed, upload.partial_failure, upload.failed and platform.failed events tell you what happened without a timer. Webhook endpoints are part of the Business plan. On other plans, a small job that lists posts and checks their status after each scheduled window does the same thing.
What does a weekly content-calendar job look like?
A common pattern is to generate or load next week's posts on a schedule you control, then submit them all at once. The CSV path is the simplest because the header is fixed: text,connections,scheduledAt,title.
# posts.csv
text,connections,scheduledAt,title
"Monday: shipping update","linkedin-mybrand","2026-12-07T09:00:00Z",""
"Wednesday: deep dive","linkedin-mybrand","2026-12-09T09:00:00Z",""
socifyr schedule posts.csv --jsonBecause each row is validated on its own, the response lists which rows failed and why, and the rest are scheduled. Fix the failed rows and resubmit only those. Running the job from cron or a CI schedule keeps the recurrence in your infrastructure, which is exactly where Socifyr expects it.
Frequently asked questions
Can I schedule posts on the free plan?
scheduledAt is rejected. Free workspaces can publish immediately. Pro and Business can schedule.How many posts can I schedule in one request?
bulk-schedule call, from a rows array or a CSV.Does the timezone field change when a post publishes?
scheduledAt fixes the instant. timezone controls display in the dashboard.Can I schedule images and video?
scheduledAt to the create call. The schedule_post and schedule_posts MCP tools are text-only.