A CMS event or spreadsheet row can become a scheduled social media post through an HTTP request. The harder part is making sure a repeated execution does not create another copy, and that the post reaches the account and time you intended.
This walkthrough describes a small publishing pipeline you can build in n8n or Make. It starts with approved content, creates a scheduled post through an API, and stores enough information to recover from failures.
The request example uses PostSider, which I build. The workflow described here has not been executed inside n8n or Make for this article.
Choose a source event, not just a timer
Start with something that makes content ready for distribution:
- A CMS article changes to published.
- A content-calendar row receives approval.
- A release announcement becomes available.
- An internal application emits an approved update. A timer can check for those events, but running the workflow should not itself authorize publication. For example, a spreadsheet-driven workflow can select records where:
approval_status = approved
publishing_job_id is empty
That selection is a starting point, not a complete duplicate-prevention mechanism. Two overlapping executions could still select the same row.
If your platform allows concurrent runs, add a claim or lock around the source record. Use API idempotency as a separate recovery mechanism.
Define the publishing record first
Keep the source data separate from the API request.
An illustrative source record might look like this:
{
"record_id": "release-announcement-042",
"revision": 1,
"approval_status": "approved",
"channel_id": "CONNECTED_ACCOUNT_ID",
"content": "The approved announcement.",
"publish_at": "2026-11-16T14:00:00Z",
"idempotency_key": "release-announcement-042-r1",
"publishing_job_id": null
}
These are your workflow fields, not a publishing API schema.
The record should identify a specific account. A platform name such as "LinkedIn" is insufficient when you manage several profiles or pages.
Store the intended publishing time before making the request. Choose a future timestamp and convert it from an explicit timezone. Do not recalculate it on each retry.
If the approved content changes, treat that as a reviewed revision rather than silently changing a request already in flight.
Use a read request to verify authentication and destination
Before creating anything, list the connected accounts.
For the API used in this example:
GET https://api.postsider.com/public/v1/integrations
Organization API keys use the raw key in the Authorization header, without a Bearer prefix.
Keep the key in credential storage. It should not appear in the source spreadsheet, exported workflow, or public example.
Inspect the returned accounts and select the intended channel ID. Do not automatically choose the first result.
A successful account-list request confirms that authentication works. It does not prove that every publishing request will be accepted.
Build the workflow in n8n
Use an HTTP Request node for the API call.
A first version can follow this sequence:
Manual Trigger
-> Read one source record
-> Check approval and required fields
-> Persist the request and idempotency key
-> HTTP Request: create scheduled post
-> Store returned post ID
-> HTTP Request: read post
-> Compare saved fields
-> Update source status
For organization-key authentication, configure a generic Header Auth credential with Authorization as the header name.
The creation node uses:
Method: POST
URL: https://api.postsider.com/public/v1/posts
Body content type: JSON
Map the caption and timestamp from the prepared record. Preserve booleans and arrays as their actual JSON types.
Start with a manual trigger and one record. Enable recurring execution only after you can inspect the created post and reconcile it with the source.
Build the equivalent scenario in Make
Use the HTTP app's Make a request module.
Configure API-key credentials to send the key in the Authorization header. Select application/json for the body content type and enable response parsing.
The request contract is the same as in n8n. The difference is how values are mapped between modules.
Use a JSON data structure for captions containing quotation marks or line breaks. Manually inserting those captions into a raw JSON string can produce invalid JSON.
Put an approval filter before the creation module. After creation, write the returned post ID to the source record rather than relying only on the scenario's execution history.
The module documentation is available in the n8n HTTP Request reference and Make HTTP reference.
Send the platform-specific request
Here is an illustrative payload for one text-only post to a connected X account:
{
"type": "schedule",
"date": "2026-11-16T14:00:00Z",
"shortLink": false,
"tags": [],
"posts": [
{
"integration": {
"id": "YOUR_X_CHANNEL_ID"
},
"value": [
{
"content": "Your approved announcement goes here.",
"image": []
}
],
"settings": {
"__type": "x",
"who_can_reply_post": "everyone"
}
}
]
}
Replace the channel ID and choose a future date before using it.
Add an Idempotency-Key header using the key already stored with your source record.
This payload is specific to X. Do not adapt it to another network by changing only the account ID. Different platforms can require different settings or media.
The full API scheduling walkthrough explains the request fields, authentication, and readback behavior behind this example.
Read the created post before updating the source
The creation response returns an array containing post IDs and integration identifiers.
For this single-destination example, retain the returned postId, then request:
GET https://api.postsider.com/public/v1/posts/RETURNED_POST_ID
The detail response contains a posts array. Find the record matching that ID and compare its content, destination, and publishDate with the prepared request.
Confirm its scheduled state before marking the source record as scheduled.
Keep "scheduled" separate from "published." A QUEUE state means the scheduler has work to perform. Publication can still fail later because of account authorization or platform requirements.
After the publishing time, check the post again. When a publication URL is available, inspect the destination result.
Make retries recover the original operation
A timeout is ambiguous. The service may have created the post even if your workflow did not receive the response.
Retry an unchanged creation request with its original idempotency key. Keep the JSON body unchanged too, including the timestamp and property order.
Generating a new key during recovery defeats that protection.
Handle failures according to their meaning:
- Timeout or transient server error: Retry with the saved key and payload, using a bounded retry policy.
- Rate-limit response: Respect the supplied retry interval.
- Validation error: Stop and inspect the request.
- Authentication failure: Repair credentials or account access before retrying.
- Conflict: Read the error; do not assume it means the post is safe to recreate. If the outcome remains unclear, reconcile the source record with the publishing calendar before making another write. Idempotency reduces duplicate creation. It does not guarantee exactly-once publication across social networks. ## Keep enough evidence to troubleshoot For each publishing operation, retain:
Source record ID and revision
Prepared request
Idempotency key
Returned post ID
Last verified state
Error details, if any
Avoid logging the authentication header.
This gives the person investigating a failure a way to identify the operation without guessing from the caption.
For multiple destinations, store the returned IDs individually. Do not mark a whole campaign as published because one account succeeded.
Test one traceable post before adding volume
Your first useful milestone is one approved source record linked to a verified scheduled post, followed by a publication check.
Once that path works, add media handling or more destinations. Keep platform-specific validation in the workflow instead of assuming every network accepts the same request.
You can then apply the same pattern to blog distribution, release announcements, or a client content calendar. The source changes, but the requirement remains: every write should have a known input and a result you can inspect.
Disclosure: I am the founder of PostSider. This article was prepared with AI assistance. The API example follows the linked implementation walkthrough; the proposed n8n and Make workflows were not executed for this article.
Top comments (1)
tr.ee/dev-to