REST API v1

Developer API Reference

Create, manage, and publish social media drafts programmatically. All endpoints require an API token: generate one in your account settings.

Prefer natural language? Use DemandBird inside Claude →

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
Keep your API token secret. Treat it like a password; don't commit it to source code or expose it in client-side JavaScript.

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

1,000
requests per hour
60
requests per minute (burst)

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

StatusMeaning
401 UnauthorizedMissing or invalid API token.
403 ForbiddenToken is valid but you don't have access to this account.
404 Not FoundDraft or resource not found.
422 Unprocessable EntityValidation failed. Check the errors array in the response body.
429 Too Many RequestsRate limit exceeded.
500 Internal Server ErrorSomething 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

GET/drafts

Returns a paginated list of drafts for the account. Defaults to draft and scheduled status.

Query parameters

ParameterTypeDescription
statusoptionalstringFilter by status. One of: draft, scheduled, posted, failed. Defaults to returning draft and scheduled combined.
pageoptionalintegerPage 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

GET/drafts/:id

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

POST/drafts

Create a new draft. The post is saved with draft status and is not published until you call the publish endpoint.

Request body (JSON)

FieldTypeDescription
contentrequiredstringThe text content of the post.
platformsoptionalarrayPlatforms to publish to. Supported values: linkedin, twitter, threads, bluesky, substack, tiktok, youtube, instagram.
scheduled_atoptionalstring (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

PATCH/drafts/:id

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)

FieldTypeDescription
contentoptionalstringNew text content for the post.
platformsoptionalarrayReplaces the current platform selection.
scheduled_atoptionalstring (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

POST/drafts/:id/publish

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.

Publishing is irreversible. Make sure the content and platforms are correct before calling this endpoint.
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

GET/posts

Returns a paginated list of posts with posted status, ordered by most-recently-updated. Filter by date range with sinceand until.

Query parameters

ParameterTypeDescription
sinceoptionalstring (ISO 8601)Return posts updated at or after this timestamp.
untiloptionalstring (ISO 8601)Return posts updated at or before this timestamp.
pageoptionalintegerPage 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

FieldTypeDescription
idintegerUnique identifier.
statusstringdraft · scheduled · posting · posted · failed
contentstringPlain-text content of the post.
platformsarray of stringsSelected publish targets.
scheduled_atstring or nullISO 8601 timestamp if a schedule was set.
published_atstring or nullISO 8601 timestamp when the post was confirmed published. null until posted.
created_atstringISO 8601 creation timestamp.
updated_atstringISO 8601 last-updated timestamp.