squidX logo

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

GETsquidx.io/api/v1/postsposts:read

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.

List posts parameters
NameInTypeDescription
statusquerystringComma-separated list of draft, queued, publishing, posted, failed, canceled. Default: every status.
limitqueryintegerRows per page, 1 to 200. Default 50.
offsetqueryintegerRows to skip. Default 0. The response meta carries the total.
Request
curl "https://squidx.io/api/v1/posts?status=queued,draft&limit=20" \
  -H "Authorization: Bearer sqx_your_key"
Response · 200
{
  "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

POSTsquidx.io/api/v1/postsposts:write

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.

Create a post parameters
NameInTypeDescription
segmentsrequiredbodyarrayOne 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.
statusbodystringdraft (default) or queued. Queuing needs a paid workspace.
scheduledAtbodystringISO 8601 instant, at least two minutes in the future. Required when status is queued, unless queueNext is true.
queueNextbodybooleanTake the next free weekly posting slot instead of a scheduledAt.
exactTimebodybooleanPublish 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.
communityIdbodystringThe X Community to post into (the number in x.com/i/communities/<id>). Omit for a normal post.
shareWithFollowersbodybooleanCommunity posts only: also show the post to followers. Default true.
autoReplybodybooleanPer-post switch for the auto-reply automation. Only sticks while the automation is enabled in Settings. Absent means the workspace default.
autoRetweetbodybooleanPer-post switch for the auto-retweet automation. Same rule as autoReply.
Request
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"
  }'
Response · 201
{
  "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

GETsquidx.io/api/v1/posts/:idposts:read

One post by id, with its segments, schedule, status, X URL once live, and metrics.

Get a post parameters
NameInTypeDescription
idrequiredpathuuidThe post id.
Request
curl https://squidx.io/api/v1/posts/0a9b8c7d-6e5f-4a3b-2c1d-0e9f8a7b6c5d \
  -H "Authorization: Bearer sqx_your_key"
Response · 200
{
  "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

PATCHsquidx.io/api/v1/posts/:idposts:write

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.

Update a post parameters
NameInTypeDescription
idrequiredpathuuidThe post id.
segmentsbodyarrayOne 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.
statusbodystringqueued, draft or canceled.
scheduledAtbodystringISO 8601 instant, at least two minutes in the future. Required when status is queued, unless queueNext is true.
queueNextbodybooleanTake the next free weekly posting slot instead of a scheduledAt.
exactTimebodybooleanPublish 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.
communityIdbodystringThe X Community to post into (the number in x.com/i/communities/<id>). Omit for a normal post.
shareWithFollowersbodybooleanCommunity posts only: also show the post to followers. Default true.
autoReplybodybooleanPer-post switch for the auto-reply automation. Only sticks while the automation is enabled in Settings. Absent means the workspace default.
autoRetweetbodybooleanPer-post switch for the auto-retweet automation. Same rule as autoReply.
Request
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 }'
Response · 200
{
  "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

DELETEsquidx.io/api/v1/posts/:idposts:write

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.

Delete a post parameters
NameInTypeDescription
idrequiredpathuuidThe post id.
Request
curl -X DELETE https://squidx.io/api/v1/posts/6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10 \
  -H "Authorization: Bearer sqx_your_key"
Response · 200
{
  "data": {
    "id": "6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10",
    "deleted": true
  }
}

Publish a post now

POSTsquidx.io/api/v1/posts/:id/publishposts:publish

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.

Publish a post now parameters
NameInTypeDescription
idrequiredpathuuidThe post id.
Request
curl -X POST https://squidx.io/api/v1/posts/6f1c2a4e-8b3d-4b1f-9c2e-2f5a7d9e1b10/publish \
  -H "Authorization: Bearer sqx_your_key"
Response · 200
{
  "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

GETsquidx.io/api/v1/posts/next-slotposts:read

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.

Request
curl https://squidx.io/api/v1/posts/next-slot \
  -H "Authorization: Bearer sqx_your_key"
Response · 200
{
  "data": {
    "at": "2026-09-25T07:00:00.000Z",
    "timezone": "Europe/Paris"
  }
}