Postspread API
Automate social media publishing, upload media, manage accounts, and pull analytics — all via a simple REST API.
Authentication
All API requests must be authenticated using a Bearer token in the Authorization header.
# Include this header with every request
Authorization: Bearer YOUR_API_KEY
# Example curl
curl https://postspread.com/api/v1/workspaces \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
Errors
Postspread uses standard HTTP status codes. All errors return a JSON body with an error or message key.
| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request — invalid parameters |
| 401 | Unauthorized — invalid or missing token |
| 403 | Forbidden — insufficient permissions or plan |
| 404 | Resource not found |
| 422 | Validation error — check the errors object |
| 500 | Server error |
Pagination
List endpoints return a data array and a meta object.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Number of items per page (default: 10) |
| page | integer | Page number (default: 1) |
{
"data": [ // array of items ],
"meta": {
"total": 48,
"offset": 0,
"limit": 10,
"next": "https://postspread.com/api/v1/posts?page=2"
}
}
Workspaces WORKSPACE
Retrieve workspaces you own. Most other endpoints scope their data to your active workspace.
Returns all workspaces the authenticated user owns.
{
"success": true,
"workspaces": [
{
"id": 1,
"name": "My Brand",
"slug": "my-brand",
"is_owner": true
}
]
}
Posts POSTS
Create, schedule, list, update, and delete social media posts.
Creates a new post. Publishes immediately or schedules it. Pass media IDs from the /media/create-upload-url endpoint.
⚠️ X (Twitter) Notes:
- X requires the Forest plan to connect
- Links in posts are automatically converted to plain text (e.g., https://example.com → example.com) because the X API charges significantly more for posts containing links
| Name | Type | Description |
|---|---|---|
| caption required | string | The text content of the post. |
| social_accounts required | integer[] | Array of social account IDs from GET /social-accounts. The workspace is resolved automatically — no workspace_id needed. |
| scheduled_at optional | datetime | ISO 8601 datetime. If omitted and is_draft is false, publishes immediately. |
| is_draft optional | boolean | Set to true to save as a draft without publishing. |
| media_urls optional | string[] | Array of public media URLs to attach. The server will download and attach them. |
| media_ids optional | integer[] | Array of Media IDs returned from <code>POST /media/create-upload-url</code>. |
| platform_configurations optional | object | Per-platform overrides keyed by platform name. E.g. <code>{"tiktok": {"draft": true}, "instagram": {"placement": "story"}}</code>. |
{
"caption": "Exciting news from our team! 🚀",
"social_accounts": [321, 456],
"scheduled_at": "2025-09-01T09:00:00Z",
"platform_configurations": {
"instagram": { "placement": "story" },
"tiktok": { "title": "Big news!" }
}
}
{
"success": true,
"post_id": 187,
"message": "Post scheduled successfully!"
}
Returns a paginated list of posts in your workspace.
| Name | Type | Description |
|---|---|---|
| limit optional | integer | Items per page (default 10). |
| status optional | string | Filter by status: draft, scheduled, published, failed. |
| platform optional | string | Filter by platform (e.g. twitter). |
{
"data": [
{
"id": 187,
"content": "Exciting news from our team! 🚀",
"platforms": ["twitter", "linkedin"],
"status": "scheduled",
"scheduled_at": "2025-09-01T09:00:00Z",
"media_urls": ["https://postspread.com/storage/uploads/photo.jpg"]
}
],
"meta": { "total": 1, "offset": 0, "limit": 10, "next": null }
}
Returns the full details of a single post.
| Name | Type | Description |
|---|---|---|
| id required | integer | Post ID. |
{
"id": 187,
"content": "Exciting news from our team! 🚀",
"platforms": ["twitter"],
"status": "published",
"published_at": "2025-09-01T09:00:00Z"
}
Update the content or schedule of an existing draft or scheduled post.
| Name | Type | Description |
|---|---|---|
| caption optional | string | New post content. |
| scheduled_at optional | datetime | New scheduled time. |
| social_accounts optional | integer[] | Array of social account IDs from GET /social-accounts. The workspace is resolved automatically — no workspace_id needed. |
| media_ids optional | integer[] | Updated media IDs. |
| platform_configurations optional | object | Updated per-platform overrides. |
{
"caption": "Updated caption text.",
"scheduled_at": "2025-09-02T10:00:00Z"
}
{
"id": 187,
"content": "Updated caption text.",
"status": "scheduled"
}
Deletes a draft or scheduled post. Published posts cannot be deleted.
| Name | Type | Description |
|---|---|---|
| id required | integer | Post ID. |
{ "success": true }
Media MEDIA
Upload images or videos and attach them to posts using the returned media_id. Uploaded media expires after 24 hours if not attached to a post.
media_id to a post promptly.Register a new media file. Returns a media_id and upload_url. Upload the binary file to the upload_url, then pass media_id to POST /posts.
| Name | Type | Description |
|---|---|---|
| name required | string | Filename including extension. E.g. photo.jpg |
| mime_type required | string | MIME type. E.g. image/jpeg, video/mp4 |
| size_bytes required | integer | File size in bytes. |
{
"name": "campaign-photo.jpg",
"mime_type": "image/jpeg",
"size_bytes": 204800
}
{
"media_id": 42,
"upload_url": "https://postspread.com/upload?media_id=42"
}
Send the actual binary file to the upload_url received from Step 1. The request MUST be sent as multipart/form-data with the file attached to the file field.
| Name | Type | Description |
|---|---|---|
| file required | file | The physical binary file to upload. |
curl -X POST "https://postspread.com/api/v1/media/upload?media_id=42" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -F "file=@/path/to/your/photo.jpg"
{
"success": true,
"media_id": 42
}
Returns all media files uploaded by the authenticated user.
| Name | Type | Description |
|---|---|---|
| limit optional | integer | Items per page (default 10). |
{
"data": [
{
"id": 42,
"original_name": "campaign-photo.jpg",
"public_url": "https://postspread.com/storage/uploads/2025/08/photo.jpg",
"mime_type": "image/jpeg",
"size": 204800,
"created_at": "2025-08-28T14:30:00Z"
}
],
"meta": { "total": 1, "offset": 0, "limit": 10, "next": null }
}
Returns the details and public URL for a single media file.
| Name | Type | Description |
|---|---|---|
| id required | integer | Media ID. |
{
"id": 42,
"original_name": "campaign-photo.jpg",
"public_url": "https://postspread.com/storage/uploads/photo.jpg",
"mime_type": "image/jpeg",
"size": 204800
}
Permanently deletes a media file and removes it from storage.
| Name | Type | Description |
|---|---|---|
| id required | integer | Media ID. |
{ "success": true }
Social Accounts ACCOUNTS
Retrieve social accounts connected to your workspace. Use the account IDs when creating posts with per-account targeting.
Returns all connected social accounts across all your workspaces.
| Name | Type | Description |
|---|---|---|
| platform optional | string | Filter by platform: twitter, instagram, linkedin, facebook, tiktok, threads, bluesky, pinterest, youtube, telegram |
| limit optional | integer | Items per page (default 10). |
{
"data": [
{
"id": 12,
"workspace_id": 199,
"platform": "instagram",
"name": "@mybrand",
"avatar": "https://..."
},
{
"id": 7,
"workspace_id": 1,
"platform": "linkedin",
"name": "My Brand",
"avatar": "https://..."
}
],
"meta": { "total": 2, "offset": 0, "limit": 10, "next": null }
}
Returns details for a single connected social account.
| Name | Type | Description |
|---|---|---|
| id required | integer | Social account ID. |
{
"id": 12,
"platform": "instagram",
"name": "@mybrand"
}
Post Results RESULTS
Retrieve the publishing results and platform responses for published posts.
Returns paginated publishing results for posts that have been processed.
| Name | Type | Description |
|---|---|---|
| post_id optional | integer | Filter results for a specific post ID. |
| limit optional | integer | Items per page (default 10). |
{
"data": [
{
"id": 187,
"post_id": 187,
"status": "published",
"results": { "twitter": "success", "linkedin": "success" },
"published_at": "2025-09-01T09:00:05Z"
}
],
"meta": { "total": 1, "offset": 0, "limit": 10, "next": null }
}
Returns the full publish result for a single post.
| Name | Type | Description |
|---|---|---|
| id required | integer | Post ID. |
{
"id": 187,
"post_id": 187,
"status": "published",
"results": { "twitter": "success" },
"published_at": "2025-09-01T09:00:05Z"
}
Analytics ANALYTICS
Retrieve engagement analytics and daily performance snapshots for your published posts.
Returns paginated analytics data for posts in your workspace.
| Name | Type | Description |
|---|---|---|
| limit optional | integer | Items per page (default 10). |
{
"data": [],
"meta": { "total": 0, "offset": 0, "limit": 10, "next": null }
}
Triggers a fresh sync of analytics data from connected platforms.
{ "success": true, "message": "Sync queued." }
Returns aggregate analytics for a single post.
| Name | Type | Description |
|---|---|---|
| id required | integer | Post ID. |
{ "id": 187, "likes": 142, "comments": 18, "shares": 6 }
Returns a day-by-day breakdown of analytics for a single post.
| Name | Type | Description |
|---|---|---|
| id required | integer | Post ID. |
{
"post_id": 187,
"daily": [
{ "date": "2025-09-01", "likes": 120, "comments": 14 },
{ "date": "2025-09-02", "likes": 22, "comments": 4 }
]
}