Authentication
Every request must include your API token as a Bearer token in the
Authorization header.
Generate a token from Settings → API Tokens.
Authorization: Bearer YOUR_API_TOKEN
Base URL
All API endpoints are relative to:
https://app.demandbird.com/api/v1/accounts/{account_id}
Your account_id is the numeric ID shown in your account settings.
All endpoints are scoped to a single account — you cannot access another account's data
even with a valid token.
Rate limits
When you exceed a limit the API returns 429 Too Many Requests with headers:
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 60
RateLimit-Remaining: 0
RateLimit-Reset: 1735689600
{"error": "Rate limit exceeded. Try again later."}
Wait until RateLimit-Reset (Unix timestamp) before retrying.
Errors
| Status | Meaning |
|---|---|
| 401 Unauthorized | Missing or invalid API token. |
| 403 Forbidden | Token is valid but you don't have access to this account. |
| 404 Not Found | Draft or resource not found. |
| 422 Unprocessable Entity | Validation failed. Check the errors array in the response body. |
| 429 Too Many Requests | Rate limit exceeded. |
| 500 Internal Server Error | Something went wrong on our end. |
Error responses always include an error or errors key:
{"error": "Draft not found"}
{"errors": ["Content can't be blank", "Platforms can't be empty"]}
List drafts
Returns a paginated list of drafts for the account.
Defaults to draft and scheduled status.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| statusoptional | string | Filter by status. One of: draft, scheduled, posted, failed. Defaults to returning draft and scheduled combined. |
| pageoptional | integer | Page number. Defaults to 1. Returns 20 results per page. |
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://app.demandbird.com/api/v1/accounts/42/drafts"
# Filter by status
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://app.demandbird.com/api/v1/accounts/42/drafts?status=scheduled"
Response:
{
"drafts": [
{
"id": 123,
"status": "draft",
"content": "Big news: we just shipped X...",
"platforms": ["linkedin", "twitter"],
"scheduled_at": null,
"published_at": null,
"created_at": "2026-03-01T09:00:00Z",
"updated_at": "2026-03-01T09:00:00Z"
}
],
"meta": {
"page": 1,
"items": 20,
"count": 42,
"pages": 3
}
}
Get a draft
Retrieve a single draft by its ID.
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://app.demandbird.com/api/v1/accounts/42/drafts/123"
Response:
{
"draft": {
"id": 123,
"status": "draft",
"content": "Big news: we just shipped X...",
"platforms": ["linkedin", "twitter"],
"scheduled_at": null,
"published_at": null,
"created_at": "2026-03-01T09:00:00Z",
"updated_at": "2026-03-01T09:00:00Z"
}
}
Create a draft
Create a new draft. The post is saved with draft status and is not published
until you call the publish endpoint.
Request body (JSON)
| Field | Type | Description |
|---|---|---|
| contentrequired | string | The text content of the post. |
| platformsoptional | array |
Platforms to publish to. Supported values:
linkedin, twitter, threads,
bluesky, substack, tiktok,
youtube, instagram.
|
| scheduled_atoptional | string (ISO 8601) | Store an intended publish time on the draft. Does not schedule the post — use publish to send immediately. |
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "Big news: we just shipped X. Here is what changed...",
"platforms": ["linkedin", "twitter"]
}' \
"https://app.demandbird.com/api/v1/accounts/42/drafts"
Returns 201 Created with the new draft:
{
"draft": {
"id": 124,
"status": "draft",
"content": "Big news: we just shipped X...",
"platforms": ["linkedin", "twitter"],
"scheduled_at": null,
"published_at": null,
"created_at": "2026-03-02T10:30:00Z",
"updated_at": "2026-03-02T10:30:00Z"
}
}
Update a draft
Update content, platforms, or scheduled time on an existing draft. All fields are optional — only send the fields you want to change.
Request body (JSON)
| Field | Type | Description |
|---|---|---|
| contentoptional | string | New text content for the post. |
| platformsoptional | array | Replaces the current platform selection. |
| scheduled_atoptional | string (ISO 8601) | Update the stored scheduled time. |
curl -X PATCH \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "Updated copy — cleaner and tighter.",
"platforms": ["linkedin"]
}' \
"https://app.demandbird.com/api/v1/accounts/42/drafts/124"
Response:
{
"draft": {
"id": 124,
"status": "draft",
"content": "Updated copy — cleaner and tighter.",
"platforms": ["linkedin"],
...
}
}
Publish a draft
Publish a draft immediately to all selected platforms. The draft must have at least one platform set — update it first if needed.
This kicks off the publishing pipeline: the post status changes to posting,
platform-specific jobs are enqueued, and the status transitions to posted
(or failed) once complete.
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
"https://app.demandbird.com/api/v1/accounts/42/drafts/124/publish"
Response:
{
"draft": {
"id": 124,
"status": "posting",
"content": "Updated copy — cleaner and tighter.",
"platforms": ["linkedin"],
"scheduled_at": "2026-03-02T11:00:00Z",
"published_at": null,
"created_at": "2026-03-02T10:30:00Z",
"updated_at": "2026-03-02T11:00:00Z"
},
"message": "Post is being published to linkedin"
}
published_at will be populated once the platform confirms the post.
Poll GET /drafts/:id to check the final status.
List published posts
Returns a paginated list of posts with posted status,
ordered by most-recently-updated. Filter by date range with since
and until.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| sinceoptional | string (ISO 8601) | Return posts updated at or after this timestamp. |
| untiloptional | string (ISO 8601) | Return posts updated at or before this timestamp. |
| pageoptional | integer | Page number. Defaults to 1. |
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://app.demandbird.com/api/v1/accounts/42/posts"
# Filter by date range
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://app.demandbird.com/api/v1/accounts/42/posts?since=2026-03-01T00:00:00Z"
Response:
{
"posts": [
{
"id": 121,
"status": "posted",
"content": "Post that went live yesterday...",
"platforms": ["linkedin"],
"scheduled_at": "2026-03-01T08:00:00Z",
"published_at": "2026-03-01T08:01:32Z",
"created_at": "2026-02-28T20:00:00Z",
"updated_at": "2026-03-01T08:01:32Z"
}
],
"meta": {
"page": 1,
"items": 20,
"count": 8,
"pages": 1
}
}
Draft object reference
| Field | Type | Description |
|---|---|---|
| id | integer | Unique identifier. |
| status | string | draft · scheduled · posting · posted · failed |
| content | string | Plain-text content of the post. |
| platforms | array of strings | Selected publish targets. |
| scheduled_at | string or null | ISO 8601 timestamp if a schedule was set. |
| published_at | string or null | ISO 8601 timestamp when the post was confirmed published. null until posted. |
| created_at | string | ISO 8601 creation timestamp. |
| updated_at | string | ISO 8601 last-updated timestamp. |