Schedule LinkedIn posts with an API
Schedule LinkedIn posts from code, a cron job or an agent.
LinkedIn's own scheduler is built for one person in a browser. This guide is for software that decides what goes out and when, including what LinkedIn's API can and can't do on its own.
The short answer · Updated Nov 1, 2026
To schedule a LinkedIn post through SocialsForAI, send POST /v1/posts with scheduled_at set to an ISO-8601 time up to 365 days ahead. The post is held, then published to every listed account when it's due. Cancel it any time before publishing starts with DELETE /v1/posts/:id; a webhook reports the result.
LinkedIn: live. Posting to LinkedIn works on the API today.
Can you schedule LinkedIn posts through the LinkedIn API?
Not directly. LinkedIn's Posts API documentation says PUBLISHED is the only lifecycleState accepted when creating a post, so there is no field for a future publish time. Scheduling has to happen on your side: store the post, then call the API at the right moment.
That is the part we run for you. You send the post once with scheduled_at; we store it, and our delivery worker, which runs every minute, publishes it through POST https://api.linkedin.com/rest/posts when it's due. Reserved characters in LinkedIn's "little" text format, such as ( ) [ ] @ *, are escaped for you, and hashtags are left intact. The LinkedIn API page covers the underlying API in more detail.
A worked example: schedule a hiring post
This schedules a post for 14:00 UTC on November 10. The timestamp must carry a time zone, either Z or an offset like -05:00; a bare local time is rejected as a validation error.
curl https://socialsforai.com/v1/posts \
-H "Authorization: Bearer $SOCIALS_API_KEY" \
-H "Idempotency-Key: hiring-staff-eng-2026-11" \
-d '{
"accounts": ["acc_linkedin_maria"],
"text": "Hiring: staff engineer, platform team. Remote in US time zones. Details and the full job description are on our careers page.",
"scheduled_at": "2026-11-10T14:00:00Z",
"metadata": { "campaign": "hiring-q4" }
}'What does a scheduled post look like?
The response is a 201 with status: "scheduled" (the text is shortened here). The target is pending with zero attempts, and next_attempt_at is the scheduled time. Your metadata comes back on the post and on every webhook, which is the easiest way to match results to rows in your own database.
{
"id": "post_7HcN2qLx9VbE0sTa",
"object": "post",
"status": "scheduled",
"text": "Hiring: staff engineer, platform team. Remote in US time zones. ...",
"media": [],
"platform_options": {},
"scheduled_at": "2026-11-10T14:00:00.000Z",
"created_at": "2026-11-01T18:20:03.511Z",
"completed_at": null,
"metadata": { "campaign": "hiring-q4" },
"targets": [
{
"id": "tgt_Lr5mW0aYp3Qe8KdZ",
"account_id": "acc_linkedin_maria",
"platform": "linkedin",
"status": "pending",
"url": null,
"external_post_id": null,
"attempts": 0,
"next_attempt_at": "2026-11-10T14:00:00.000Z",
"published_at": null,
"verified": false,
"error": null
}
]
}What happens when the scheduled time arrives?
Within about a minute of scheduled_at, the post moves to publishing, then published. The target gets LinkedIn's post URN (from the x-restli-id header LinkedIn returns with its 201) and a https://www.linkedin.com/feed/update/... URL, and a post.published webhook fires with the full post.
Before publishing, we check the account is still connected. Everything else, such as length and duplicates, was checked when you created the post. If LinkedIn returns 429 or a 5xx, the attempt is retried after 30s, 2m, 10m, 30m and 2h, six attempts in all, before the target is marked failed and post.failed fires.
In TypeScript, the webhook handler verifies the Socials-Signature header (HMAC-SHA256 of the timestamp and raw body) before trusting the event:
import { createHmac, timingSafeEqual } from "node:crypto";
export async function POST(req: Request) {
const raw = await req.text();
const sig = req.headers.get("Socials-Signature") ?? ""; // t=<unix>,v1=<hex>
const { t, v1 } = Object.fromEntries(sig.split(",").map((p) => p.split("=")));
const expected = createHmac("sha256", process.env.SOCIALS_WEBHOOK_SECRET!).update(`${t}.${raw}`).digest("hex");
const ok = !!v1 && v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
if (!ok) return new Response("bad signature", { status: 400 });
const event = JSON.parse(raw); // { type: "post.published", data: { post } }
if (event.type === "post.failed") console.error(event.data.post.targets[0].error);
return new Response("ok");
}How do I edit or cancel a scheduled LinkedIn post?
There is no edit endpoint. Cancel the post with DELETE /v1/posts/:id and create a new one. Canceling works while no target has started publishing; after that it returns 409 post_not_cancelable, and the published copy has to be deleted on LinkedIn.
When you recreate the post, use a new idempotency key. Sending the old key with a different body returns 409 idempotency_key_reused. A canceled post fires post.canceled.
Why would a scheduled LinkedIn post fail?
The most common cause is an expired token. LinkedIn access tokens last 60 days, and without LinkedIn partner access there is no refresh token. A post scheduled 90 days after the profile was connected is sent with an expired token; LinkedIn rejects it, the account moves to needs_reauth, and the target fails with account_needs_reauth, which doesn't retry.
Plan for it: every account carries connected_at, so send the profile owner a fresh connect link before 60 days pass, and listen for the account.needs_reauth webhook to catch the ones you miss. The other failures are covered in the troubleshooting list below.
text_too_long: over 3,000 characters. Shorten it; see the LinkedIn character limit page.scheduled_in_past:scheduled_atis more than 5 minutes in the past. Pass a future time, or omit it to publish now.scheduled_too_far: more than 365 days ahead.duplicate_content: the same text is already published or queued on this account from the last 24 hours. This counts when the post was created, not when it publishes, so two identical posts created today for different weeks still collide.daily_cap_reached: 50 posts created for this LinkedIn account in 24 hours, scheduled ones included. Load long queues a few days at a time.too_many_media: more than 20 images. Images are uploaded through LinkedIn's Images API, up to 20 MB each.
When is LinkedIn's own scheduler the better choice?
If one person writes and schedules their own posts by hand, use LinkedIn's built-in scheduler. LinkedIn Help says you can schedule a post between 10 minutes and 3 months ahead, on desktop or mobile, and edit, reschedule or delete it from the Scheduled posts page. Event and job posts can't be scheduled there.
We have no calendar or composer. We're the better fit when software decides what to post: an app posting for its users, an agency system posting for many clients, or an AI agent running through our LinkedIn MCP server. We also support up to 365 days ahead and the same call reaches X and Bluesky; see crossposting. We post to personal profiles only for now, not company pages.
How to schedule a LinkedIn post with the API
Five calls, most of them one-time setup.
- 01
Get an API key
POST https://socialsforai.com/v1/workspaces returns an api_key (sk_...). Store it; it is shown once.
- 02
Connect the LinkedIn profile
POST /v1/connect-links with platforms set to linkedin. The person whose profile it is opens the url, signs in to LinkedIn and approves posting (the w_member_social permission). You get an account id (acc_...).
- 03
Check the post with a dry run
Send the post with dry_run: true and your scheduled_at. You get back ok: true, or a list of issues such as text_too_long or scheduled_in_past, each with a fix. Nothing is stored.
- 04
Schedule it
Send the same body without dry_run. The response is 201 with status scheduled. Keep the post id.
- 05
Get told when it publishes
Register a webhook for post.published and post.failed with POST /v1/webhooks, or poll GET /v1/posts/:id. To change your mind, DELETE /v1/posts/:id before the scheduled time.
Questions
What developers ask
How far ahead can I schedule a LinkedIn post?
Through our API, up to 365 days ahead; anything later fails preflight with scheduled_too_far. LinkedIn's own scheduler allows 10 minutes to 3 months, per LinkedIn Help. Because LinkedIn tokens last 60 days without partner access, posts scheduled further out need the profile owner to reconnect before they come due.
Can I edit a scheduled LinkedIn post?
Not in place. Cancel it with DELETE /v1/posts/:id and create a new post with a new idempotency key. Canceling works until the post starts publishing; after that the API returns 409 post_not_cancelable, and you would delete the published post on LinkedIn itself.
Can I schedule posts to a LinkedIn company page?
Not yet. We post to personal profiles using LinkedIn's w_member_social permission. Posting as a company page uses w_organization_social, which LinkedIn restricts to members with an admin or content role on that page, and we haven't built it. For pages today, LinkedIn's own Page scheduler is the option.
Does the LinkedIn API support scheduled posts natively?
No. LinkedIn's Posts API documentation says PUBLISHED is the only lifecycleState accepted when a post is created, so there is no future publish time field. Any tool that schedules LinkedIn posts through the API stores the post and calls LinkedIn at the scheduled time, which is what our delivery worker does every minute.
How do I know a scheduled LinkedIn post went out?
Register a webhook for post.published and post.failed. The published event includes the post with LinkedIn's URN and URL on each target. Each request carries a Socials-Signature header, an HMAC-SHA256 of the timestamp and raw body, so you can verify it came from us. Polling GET /v1/posts/:id works too.
Can an AI agent schedule LinkedIn posts?
Yes. Connect our MCP server to Claude Code, Cursor or another MCP client, and the agent gets a create_post tool that accepts the same scheduled_at field. It can also call list_posts and cancel_post. The agent never sees LinkedIn credentials; it works with account ids.
Get an API key and send your first post in five minutes.