DemandBird exact-time LinkedIn post
Use this skill when an approved LinkedIn post (text, image or PDF carousel) must go out at a specific minute through DemandBird. Produces a scheduled post whose stored copy, time and media match what was approved, confirmed by one read-back. Uses DemandBird's MCP server. "Schedule this post for Tuesday 10am", "queue the carousel", "schedule the week's LinkedIn posts".
Applies when approved LinkedIn copy has to land at an exact time, often for a client or a launch. Produces a scheduled DemandBird post that matches the approval, with the read-back saved as proof.
Needs DemandBird's MCP server connected with a token scoped to drafting and scheduling. Leave deletion out of the token.
The play
- Call
list_connected_accountsandlist_scheduled_posts. Take the LinkedIn account ID from the result, never from memory, and check nothing is already queued in that slot. - Save the approved copy verbatim with
save_draft:content,platforms: ["linkedin"], the account inplatform_account_ids, and any media inimages. Don't run it through a drafting or voice tool; that rewrites approved copy. - For a PDF carousel, set the document
titleexplicitly. Otherwise LinkedIn shows the filename. - Call
schedule_postwith the post ID,scheduled_atas ISO 8601 with the UTC offset for that date, andvariance_minutes: 0. Without the zero, the account's default jitter moves the time. - Call
get_postonce. Compare it with the approved file: copy (only a trailing newline may differ), time, media and status. Save that read-back. Don't poll. - Record the post as scheduled with its ID and time. There is no public URL until it publishes; fill it in afterwards.
Media and first-comment quirks, and the rate-limit behaviour, are in references/demandbird-quirks.md. Open it before a batch.
What good looks like
- First check: the stored time and variance. A post "scheduled for 3pm" that stores a window instead of 3:00 never had its variance set to zero.
- The mediocre version loops
save_draftover a week of posts. The first rate-limit rejection doesn't stop the loop, and every later call fails or, worse, half-succeeds. - The output is right when each read-back matches the approved copy byte for byte (bar the trailing newline), the time is exact in the offset for that date, and there is exactly one post per slot.
Rules
- MUST have approval for the copy, media, account and dated time of every post, batch rows included; save the copy verbatim.
- MUST set
variance_minutes: 0when the time matters. - MUST stop a batch on the first rejection, wait, and reconcile with
list_scheduled_postsbefore retrying. A rejected write doesn't prove nothing was created. - NEVER mark a first comment verified from
get_post; it doesn't return them. - NEVER give the agent a token that can delete posts or manage channels.
references/demandbird-quirks.md
DemandBird quirks
Each of these showed up while scheduling weekly LinkedIn posts through the MCP server.
Time
- Jitter. Accounts can carry a default variance window around the scheduled time.
variance_minutes: 0onschedule_poststores the exact time. Use a deliberate variance only when you want it. - Offsets. Send
scheduled_atwith the offset that applies on that date (-04:00versus-05:00across a daylight-saving change). Keep the wall-clock time the human approved.
Copy
- Trailing newline. The stored content drops a trailing newline. Treat that as the one allowed difference when comparing.
- No voice pass. Saving with
save_draftstores your text verbatim. Drafting tools generate new copy; don't use them on approved text. - Mentions. No person-mention (tagging) field turned up in the tools. Tag by hand after publishing if needed.
Media
| Input | What happens | Do |
|---|---|---|
| PNG image | re-encoded to JPEG, dimensions kept | expect it; check it isn't cropped |
| PDF carousel | document title defaults to the filename | set title |
| large file | uploads around 100 MB worked | upload once, reuse the reference |
First comments
save_drafttakesfirst_comment: {text, delay_minutes}.- First comments are text only. A comment that needs an image has to be posted by hand.
get_postdoesn't return first comments, so the save acknowledgement is the only evidence before publishing. Check the live post afterwards.
Rate limits
- A rejection carries no reset header, and the limit that applies to MCP calls isn't published.
- A batch that kept going after the first rejection wasted four calls and left drafts half-made.
- Pattern that works: one post at a time, stop at the first rejection, wait about a minute, run
list_scheduled_posts, then continue only with posts that aren't there. Check drafts too: reuse a draft the failed call left behind rather than saving a second one. - One read-back per post. Polling
get_postspends the same budget.
Token scope
A token scoped to create, edit, schedule and read was enough for this whole procedure. Leave out deletion, review decisions and channel management.