Posts
Create, read, update, and delete posts
Posts
Posts are the core resource in the Octopost API. A post contains content that can be published to one or more social media platforms simultaneously.
The Post Object
{
"id": "post_abc123",
"content": "Check out our new feature launch!",
"platforms": ["twitter", "bluesky", "linkedin"],
"status": "published",
"scheduled_for": null,
"media": {
"images": [
{
"url": "https://cdn.octopost.ink/uploads/img_001.png",
"alt_text": "Screenshot of the new dashboard"
}
],
"video": null
},
"platform_results": {
"twitter": {
"success": true,
"post_id": "1234567890",
"post_url": "https://x.com/user/status/1234567890"
},
"bluesky": {
"success": true,
"post_id": "at://did:plc:abc/app.bsky.feed.post/xyz",
"post_url": "https://bsky.app/profile/user.bsky.social/post/xyz"
},
"linkedin": {
"success": false,
"error": "Token expired. Reconnect your LinkedIn account."
}
},
"created_at": "2026-04-03T12:00:00Z",
"updated_at": "2026-04-03T12:05:00Z",
"published_at": "2026-04-03T12:05:00Z"
}Status Values
| Status | Description |
|---|---|
draft | Created but not yet published or scheduled |
scheduled | Queued for publishing at scheduled_for time |
publishing | Currently being published to platforms |
published | Successfully published to at least one platform |
failed | Publishing failed on all platforms |
Create a Post
POST /posts
Creates a new post. The post is created in draft status unless scheduled_for is provided, in which case it is created in scheduled status.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | The post content. Platform-specific character limits are validated at publish time. |
platforms | string[] | Yes | Array of platform identifiers to publish to. Valid values: twitter, bluesky, mastodon, linkedin, threads, instagram, facebook, tiktok, youtube. |
scheduled_for | string | No | ISO 8601 datetime for scheduled publishing. Must be in the future. |
media | object | No | Media attachments. See Media Object below. |
Media Object
| Field | Type | Description |
|---|---|---|
images | array | Array of image objects, each with url (string, required) and alt_text (string, optional). Maximum 4 images. |
video | object | Video object with url (string, required) and thumbnail_url (string, optional). Cannot be combined with images. |
Example: Create a Draft Post
curl -X POST https://api.octopost.ink/v1/posts \
-H "Authorization: Bearer oct_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"content": "Excited to announce our Series A!",
"platforms": ["twitter", "linkedin", "bluesky"]
}'{
"id": "post_def456",
"content": "Excited to announce our Series A!",
"platforms": ["twitter", "linkedin", "bluesky"],
"status": "draft",
"scheduled_for": null,
"media": null,
"platform_results": null,
"created_at": "2026-04-03T14:00:00Z",
"updated_at": "2026-04-03T14:00:00Z",
"published_at": null
}Example: Create a Scheduled Post with Media
curl -X POST https://api.octopost.ink/v1/posts \
-H "Authorization: Bearer oct_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"content": "New blog post: Building a cross-posting API",
"platforms": ["twitter", "bluesky"],
"scheduled_for": "2026-04-10T09:00:00Z",
"media": {
"images": [
{
"url": "https://example.com/blog-header.png",
"alt_text": "Blog post header image"
}
]
}
}'{
"id": "post_ghi789",
"content": "New blog post: Building a cross-posting API",
"platforms": ["twitter", "bluesky"],
"status": "scheduled",
"scheduled_for": "2026-04-10T09:00:00Z",
"media": {
"images": [
{
"url": "https://example.com/blog-header.png",
"alt_text": "Blog post header image"
}
],
"video": null
},
"platform_results": null,
"created_at": "2026-04-03T14:00:00Z",
"updated_at": "2026-04-03T14:00:00Z",
"published_at": null
}List Posts
GET /posts
Returns a paginated list of posts.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | - | Filter by status: published, scheduled, draft, failed. |
limit | integer | 10 | Number of posts to return. Maximum 100. |
offset | integer | 0 | Number of posts to skip for pagination. |
Example
curl "https://api.octopost.ink/v1/posts?status=published&limit=5&offset=0" \
-H "Authorization: Bearer oct_live_abc123"{
"posts": [
{
"id": "post_abc123",
"content": "Check out our new feature launch!",
"platforms": ["twitter", "bluesky"],
"status": "published",
"scheduled_for": null,
"media": null,
"platform_results": {
"twitter": {
"success": true,
"post_id": "1234567890",
"post_url": "https://x.com/user/status/1234567890"
},
"bluesky": {
"success": true,
"post_id": "at://did:plc:abc/app.bsky.feed.post/xyz",
"post_url": "https://bsky.app/profile/user.bsky.social/post/xyz"
}
},
"created_at": "2026-04-03T12:00:00Z",
"updated_at": "2026-04-03T12:05:00Z",
"published_at": "2026-04-03T12:05:00Z"
}
],
"total": 42
}Get a Post
GET /posts/:id
Returns a single post by ID.
Example
curl https://api.octopost.ink/v1/posts/post_abc123 \
-H "Authorization: Bearer oct_live_abc123"{
"id": "post_abc123",
"content": "Check out our new feature launch!",
"platforms": ["twitter", "bluesky"],
"status": "published",
"scheduled_for": null,
"media": null,
"platform_results": {
"twitter": {
"success": true,
"post_id": "1234567890",
"post_url": "https://x.com/user/status/1234567890"
},
"bluesky": {
"success": true,
"post_id": "at://did:plc:abc/app.bsky.feed.post/xyz",
"post_url": "https://bsky.app/profile/user.bsky.social/post/xyz"
}
},
"created_at": "2026-04-03T12:00:00Z",
"updated_at": "2026-04-03T12:05:00Z",
"published_at": "2026-04-03T12:05:00Z"
}Returns 404 Not Found if the post does not exist.
Update a Post
PUT /posts/:id
Updates a post. Only posts in draft or scheduled status can be updated. Attempting to update a published or publishing post returns 409 Conflict.
Request Body
All fields are optional. Only include the fields you want to change.
| Field | Type | Description |
|---|---|---|
content | string | Updated post content. |
platforms | string[] | Updated list of target platforms. |
scheduled_for | string | null | Updated schedule time (ISO 8601), or null to unschedule. |
media | object | null | Updated media attachments, or null to remove media. |
Example
curl -X PUT https://api.octopost.ink/v1/posts/post_def456 \
-H "Authorization: Bearer oct_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"content": "Excited to announce our Series A! Read more on our blog.",
"platforms": ["twitter", "linkedin", "bluesky", "threads"]
}'{
"id": "post_def456",
"content": "Excited to announce our Series A! Read more on our blog.",
"platforms": ["twitter", "linkedin", "bluesky", "threads"],
"status": "draft",
"scheduled_for": null,
"media": null,
"platform_results": null,
"created_at": "2026-04-03T14:00:00Z",
"updated_at": "2026-04-03T14:10:00Z",
"published_at": null
}Delete a Post
DELETE /posts/:id
Deletes a post. Published posts are removed from Octopost but are not deleted from the social platforms they were published to. To delete from platforms, use the platform's native tools.
Example
curl -X DELETE https://api.octopost.ink/v1/posts/post_def456 \
-H "Authorization: Bearer oct_live_abc123"Returns 204 No Content on success.
Publish a Post
POST /posts/:id/publish
Immediately publishes a post to all specified platforms. The post must be in draft or scheduled status. Publishing is asynchronous -- the endpoint returns immediately with status publishing, and platform results are populated as each platform completes.
Use webhooks to be notified when publishing completes, or poll the post endpoint.
Example
curl -X POST https://api.octopost.ink/v1/posts/post_def456/publish \
-H "Authorization: Bearer oct_live_abc123"{
"id": "post_def456",
"content": "Excited to announce our Series A! Read more on our blog.",
"platforms": ["twitter", "linkedin", "bluesky", "threads"],
"status": "publishing",
"scheduled_for": null,
"media": null,
"platform_results": null,
"created_at": "2026-04-03T14:00:00Z",
"updated_at": "2026-04-03T14:15:00Z",
"published_at": null
}After publishing completes, a subsequent GET /posts/post_def456 returns the full platform_results:
{
"id": "post_def456",
"status": "published",
"platform_results": {
"twitter": {
"success": true,
"post_id": "1234567891",
"post_url": "https://x.com/user/status/1234567891"
},
"linkedin": {
"success": true,
"post_id": "urn:li:share:7890",
"post_url": "https://www.linkedin.com/feed/update/urn:li:share:7890"
},
"bluesky": {
"success": true,
"post_id": "at://did:plc:abc/app.bsky.feed.post/def",
"post_url": "https://bsky.app/profile/user.bsky.social/post/def"
},
"threads": {
"success": true,
"post_id": "17890012345",
"post_url": "https://www.threads.net/@user/post/17890012345"
}
},
"published_at": "2026-04-03T14:15:05Z"
}Errors
| Code | Reason |
|---|---|
409 Conflict | Post is already published or currently publishing. |
422 Validation Error | Content exceeds character limit for one or more platforms, or no valid connected accounts found for the specified platforms. |