Posts
Drafts, the queue and the published record, as one resource with a status. A post is a list of segments: one segment is a single post, several make a thread that squidX chains at publish time.
List posts
Posts of the workspace, scheduled ones first (soonest first), then the rest newest first. Posted rows carry their public metrics once the daily analytics run has seen them; until then metrics is null.
| Name | In | Type | Description |
|---|---|---|---|
status | query | string | Comma-separated list of draft, queued, publishing, posted, failed, canceled. Default: every status. |
limit | query | integer | Rows per page, 1 to 200. Default 50. |
offset | query | integer | Rows to skip. Default 0. The response meta carries the total. |
curl "https://squidx.io/api/v1/posts?status=queued,draft&limit=20" \
-H "Authorization: Bearer sqx_your_key"{
"data": [
{
"id": "6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10",
"status": "queued",
"segments": [
{
"text": "We just opened the squidX API. Schedule posts from anywhere.",
"media": []
},
{
"text": "Docs and MCP setup in the reply.",
"media": []
}
],
"scheduledAt": "2026-09-24T09:00:00.000Z",
"publishAt": "2026-09-24T09:02:37.000Z",
"exactTime": false,
"communityId": null,
"shareWithFollowers": true,
"source": "composer",
"publishedIds": [],
"url": null,
"postedAt": null,
"lastError": null,
"autoReply": {
"enabled": true,
"status": null,
"postId": null
},
"autoRetweet": {
"enabled": false,
"status": null
},
"metrics": null,
"createdAt": "2026-09-23T14:02:11.000Z",
"updatedAt": "2026-09-23T14:02:11.000Z"
}
],
"meta": {
"total": 1,
"limit": 20,
"offset": 0
}
}Create a post
Create a draft, or queue a post in one call. The response is the post as squidX stored it: publishAt is scheduledAt plus the jitter that was picked at queue time.
| Name | In | Type | Description |
|---|---|---|---|
segmentsrequired | body | array | One entry per post of the thread, in order. An entry is a string, or { text, media: [{ id }] } where id comes from POST /media. Up to 25 entries. Each text is capped at 280 weighted characters, or 25,000 when the workspace allows long posts. |
status | body | string | draft (default) or queued. Queuing needs a paid workspace. |
scheduledAt | body | string | ISO 8601 instant, at least two minutes in the future. Required when status is queued, unless queueNext is true. |
queueNext | body | boolean | Take the next free weekly posting slot instead of a scheduledAt. |
exactTime | body | boolean | Publish at the exact instant. By default squidX adds one to four minutes of jitter either side, so the queue does not look like a robot. |
communityId | body | string | The X Community to post into (the number in x.com/i/communities/<id>). Omit for a normal post. |
shareWithFollowers | body | boolean | Community posts only: also show the post to followers. Default true. |
autoReply | body | boolean | Per-post switch for the auto-reply automation. Only sticks while the automation is enabled in Settings. Absent means the workspace default. |
autoRetweet | body | boolean | Per-post switch for the auto-retweet automation. Same rule as autoReply. |
curl -X POST https://squidx.io/api/v1/posts \
-H "Authorization: Bearer sqx_your_key" \
-H "Content-Type: application/json" \
-d '{
"segments": [
"We just opened the squidX API. Schedule posts from anywhere.",
"Docs and MCP setup in the reply."
],
"status": "queued",
"scheduledAt": "2026-09-24T09:00:00Z"
}'{
"data": {
"id": "6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10",
"status": "queued",
"segments": [
{
"text": "We just opened the squidX API. Schedule posts from anywhere.",
"media": []
},
{
"text": "Docs and MCP setup in the reply.",
"media": []
}
],
"scheduledAt": "2026-09-24T09:00:00.000Z",
"publishAt": "2026-09-24T09:02:37.000Z",
"exactTime": false,
"communityId": null,
"shareWithFollowers": true,
"source": "composer",
"publishedIds": [],
"url": null,
"postedAt": null,
"lastError": null,
"autoReply": {
"enabled": true,
"status": null,
"postId": null
},
"autoRetweet": {
"enabled": false,
"status": null
},
"metrics": null,
"createdAt": "2026-09-23T14:02:11.000Z",
"updatedAt": "2026-09-23T14:02:11.000Z"
}
}- Use queueNext: true instead of scheduledAt to drop the post into the next free posting slot.
- Creating never needs the tweet.write scope on the X connection. Publishing does; a queued post whose connection cannot write surfaces needs_reconnect in the dashboard before it is due.
Get a post
One post by id, with its segments, schedule, status, X URL once live, and metrics.
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | uuid | The post id. |
curl https://squidx.io/api/v1/posts/0a9b8c7d-6e5f-4a3b-2c1d-0e9f8a7b6c5d \
-H "Authorization: Bearer sqx_your_key"{
"data": {
"id": "0a9b8c7d-6e5f-4a3b-2c1d-0e9f8a7b6c5d",
"status": "posted",
"segments": [
{
"text": "Built a thing. Here is what I learned.",
"media": []
}
],
"scheduledAt": "2026-09-20T09:00:00.000Z",
"publishAt": "2026-09-20T09:01:12.000Z",
"exactTime": false,
"communityId": null,
"shareWithFollowers": true,
"source": "composer",
"publishedIds": [
"1969431290813001729"
],
"url": "https://x.com/aschapmann/status/1969431290813001729",
"postedAt": "2026-09-20T09:01:13.000Z",
"lastError": null,
"autoReply": {
"enabled": true,
"status": "done",
"postId": "1969470001234567890"
},
"autoRetweet": {
"enabled": false,
"status": null
},
"metrics": {
"impressions": 18420,
"likes": 212,
"replies": 34,
"reposts": 19,
"quotes": 4,
"bookmarks": 61,
"engagements": 330,
"engagementRate": 0.0179,
"updatedAt": "2026-09-23T04:00:41.000Z"
},
"createdAt": "2026-09-19T21:40:00.000Z",
"updatedAt": "2026-09-20T09:01:13.000Z"
}
}Update a post
Edit a draft, queued or failed post. Send only the fields to change. status moves the post: queued schedules it (with scheduledAt or queueNext), draft takes it out of the queue, canceled cancels it. A post the cron has claimed answers 409.
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | uuid | The post id. |
segments | body | array | One entry per post of the thread, in order. An entry is a string, or { text, media: [{ id }] } where id comes from POST /media. Up to 25 entries. Each text is capped at 280 weighted characters, or 25,000 when the workspace allows long posts. |
status | body | string | queued, draft or canceled. |
scheduledAt | body | string | ISO 8601 instant, at least two minutes in the future. Required when status is queued, unless queueNext is true. |
queueNext | body | boolean | Take the next free weekly posting slot instead of a scheduledAt. |
exactTime | body | boolean | Publish at the exact instant. By default squidX adds one to four minutes of jitter either side, so the queue does not look like a robot. |
communityId | body | string | The X Community to post into (the number in x.com/i/communities/<id>). Omit for a normal post. |
shareWithFollowers | body | boolean | Community posts only: also show the post to followers. Default true. |
autoReply | body | boolean | Per-post switch for the auto-reply automation. Only sticks while the automation is enabled in Settings. Absent means the workspace default. |
autoRetweet | body | boolean | Per-post switch for the auto-retweet automation. Same rule as autoReply. |
curl -X PATCH https://squidx.io/api/v1/posts/6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10 \
-H "Authorization: Bearer sqx_your_key" \
-H "Content-Type: application/json" \
-d '{ "status": "queued", "queueNext": true }'{
"data": {
"id": "6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10",
"status": "queued",
"segments": [
{
"text": "We just opened the squidX API. Schedule posts from anywhere.",
"media": []
},
{
"text": "Docs and MCP setup in the reply.",
"media": []
}
],
"scheduledAt": "2026-09-25T07:00:00.000Z",
"publishAt": "2026-09-25T06:58:20.000Z",
"exactTime": false,
"communityId": null,
"shareWithFollowers": true,
"source": "composer",
"publishedIds": [],
"url": null,
"postedAt": null,
"lastError": null,
"autoReply": {
"enabled": true,
"status": null,
"postId": null
},
"autoRetweet": {
"enabled": false,
"status": null
},
"metrics": null,
"createdAt": "2026-09-23T14:02:11.000Z",
"updatedAt": "2026-09-23T14:02:11.000Z"
}
}Delete a post
Delete a draft, queued, failed or canceled post and its attachments. A post that is on X, or on its way, answers 409: it cannot be deleted from here.
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | uuid | The post id. |
curl -X DELETE https://squidx.io/api/v1/posts/6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10 \
-H "Authorization: Bearer sqx_your_key"{
"data": {
"id": "6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10",
"deleted": true
}
}Publish a post now
Send a draft, queued or failed post to X immediately, inside the request. Needs the posts:publish permission and a paid workspace. Never retry a publish call on a timeout: read the post back first, it may be live.
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | uuid | The post id. |
curl -X POST https://squidx.io/api/v1/posts/6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10/publish \
-H "Authorization: Bearer sqx_your_key"{
"data": {
"id": "6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10",
"status": "posted",
"segments": [
{
"text": "Built a thing. Here is what I learned.",
"media": []
}
],
"scheduledAt": null,
"publishAt": null,
"exactTime": false,
"communityId": null,
"shareWithFollowers": true,
"source": "composer",
"publishedIds": [
"1969431290813001729"
],
"url": "https://x.com/aschapmann/status/1969431290813001729",
"postedAt": "2026-09-20T09:01:13.000Z",
"lastError": null,
"autoReply": {
"enabled": true,
"status": "pending",
"postId": null
},
"autoRetweet": {
"enabled": false,
"status": null
},
"metrics": null,
"createdAt": "2026-09-19T21:40:00.000Z",
"updatedAt": "2026-09-20T09:01:13.000Z"
}
}- A refusal that provably wrote nothing (duplicate, rate limit, refused image, lost community) leaves the post exactly where it was, with the code in the error body.
- A failure that may have reached X (timeout, network, 5xx) parks the post as failed with lastError set. Part of a thread may be live; the dashboard shows which segments made it.
- Publishing counts against the daily cap of 25 posts per workspace. Past it the call answers 429 daily_limit.
Get the next posting slot
Where queueNext would land right now: the next weekly posting slot not already taken by a queued post. at is null when the workspace has no schedule.
curl https://squidx.io/api/v1/posts/next-slot \
-H "Authorization: Bearer sqx_your_key"{
"data": {
"at": "2026-09-25T07:00:00.000Z",
"timezone": "Europe/Paris"
}
}