API reference

Campaigns

10 endpoints, served at https://orbitwrite.com/api/v1. Each one lists the credentials it accepts, its parameters and every response it can give.

List a workspace's campaigns#

GET/api/v1/campaigns

Requires campaign:read. Returns the organization's campaigns, newest first, each with a post count and the next upcoming scheduled post.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Query parameters

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

Responses

200CampaignList

The workspace's campaigns

Response attributes
campaignsCampaign[]Required
Child attributes
idstringRequired
titlestring | nullRequired
descriptionstring | nullRequired

The campaign's context/source text.

colorstringRequired
iconstring | nullRequired
startDatestring | nullRequired

ISO 8601

endDatestring | nullRequired

ISO 8601

postCountintegerRequired

Every post generated for the campaign, any status

nextScheduledAtstring | nullRequired

ISO 8601 of the soonest still-upcoming scheduled post

firstScheduledAtstring | nullRequired

ISO 8601 of the earliest fire time among the campaign's posts, any status; null when none has one (drafts have no fire time). With lastScheduledAt, the span a calendar draws the campaign over when startDate/endDate are unset.

lastScheduledAtstring | nullRequired

ISO 8601 of the latest fire time among the campaign's posts, any status; null when none has one.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/campaigns
curl -X GET "https://orbitwrite.com/api/v1/campaigns" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "campaigns": [
    {
      "id": "string",
      "title": "string",
      "description": "string",
      "color": "string",
      "icon": "string",
      "startDate": "string",
      "endDate": "string",
      "postCount": 0,
      "nextScheduledAt": "string",
      "firstScheduledAt": "string",
      "lastScheduledAt": "string"
    }
  ]
}

Create a bare campaign#

POST/api/v1/campaigns

Requires campaign:create. Creates a campaign with no posts. The AI wizard generates posts separately; this is the lightweight counterpart used by the create modal and inline composer form.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

titlestringRequired

Between 1 and 200 characters.

descriptionstring

At most 4000 characters.

colorstring

Palette color id (shares the tag palette). Omit to keep the default.

  • "grey"
  • "dark-grey"
  • "purple"
  • "blue"
  • "teal"
  • "green"
  • "yellow"
  • "orange"
  • "pink"
  • "red"
iconstring | null

Avatar icon as a prefixed string: emoji:🚀 for a raw emoji, or hi:Rocket01 for a curated hugeicon. Null clears it back to the letter monogram.

At most 64 characters.

startDatestring | null

Format date-time.

endDatestring | null

Format date-time.

Responses

200CampaignRefResult

The created campaign

Response attributes
okbooleanRequired
campaignCampaignRefRequired
Child attributes
idstringRequired
titlestring | nullRequired
descriptionstring | nullRequired
colorstringRequired
iconstring | nullRequired
startDatestring | nullRequired
endDatestring | nullRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/campaigns
curl -X POST "https://orbitwrite.com/api/v1/campaigns" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "string"
}'
Response
{
  "ok": true,
  "campaign": {
    "id": "string",
    "title": "string",
    "description": "string",
    "color": "string",
    "icon": "string",
    "startDate": "string",
    "endDate": "string"
  }
}

Search campaigns by name#

GET/api/v1/campaigns/search

Requires campaign:read. Case-insensitive substring match against the campaign title, scoped to the organization. LIKE metacharacters in the query match literally. Powers the command menu's campaign search. Returns at most 20 campaigns, newest first.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Query parameters

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

qstringRequired

At least 1 character.

Responses

200SearchCampaignsResult

Matching campaigns, newest first

Response attributes
itemsSearchCampaignItem[]Required
Child attributes
idstringRequired
titlestring | nullRequired
colorstringRequired
iconstring | nullRequired

Prefixed avatar-icon string (emoji:🚀 / hi:Rocket01), or null when the campaign has no custom icon.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
429Error

Rate limit exceeded

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/campaigns/search
curl -X GET "https://orbitwrite.com/api/v1/campaigns/search?q=q" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "color": "string",
      "icon": "string"
    }
  ]
}

Get a campaign#

GET/api/v1/campaigns/{campaignId}

Requires campaign:read. One campaign, with the same post count and next scheduled post the list carries. Its posts are GET /posts?campaignId=.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

campaignIdstringRequired

At least 1 character.

Responses

200Campaign

The campaign

Response attributes
idstringRequired
titlestring | nullRequired
descriptionstring | nullRequired

The campaign's context/source text.

colorstringRequired
iconstring | nullRequired
startDatestring | nullRequired

ISO 8601

endDatestring | nullRequired

ISO 8601

postCountintegerRequired

Every post generated for the campaign, any status

nextScheduledAtstring | nullRequired

ISO 8601 of the soonest still-upcoming scheduled post

firstScheduledAtstring | nullRequired

ISO 8601 of the earliest fire time among the campaign's posts, any status; null when none has one (drafts have no fire time). With lastScheduledAt, the span a calendar draws the campaign over when startDate/endDate are unset.

lastScheduledAtstring | nullRequired

ISO 8601 of the latest fire time among the campaign's posts, any status; null when none has one.

401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/campaigns/{campaignId}
curl -X GET "https://orbitwrite.com/api/v1/campaigns/{campaignId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "id": "string",
  "title": "string",
  "description": "string",
  "color": "string",
  "icon": "string",
  "startDate": "string",
  "endDate": "string",
  "postCount": 0,
  "nextScheduledAt": "string",
  "firstScheduledAt": "string",
  "lastScheduledAt": "string"
}

Update a campaign's metadata#

PATCH/api/v1/campaigns/{campaignId}

Requires campaign:update. Edit a campaign's name, description, colour, and date range.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

campaignIdstringRequired

At least 1 character.

Body application/json

titlestringRequired

Between 1 and 200 characters.

descriptionstring

Omit to keep the stored description; send an empty string to clear it.

At most 4000 characters.

colorstring

Palette color id (shares the tag palette). Omit to keep the default.

  • "grey"
  • "dark-grey"
  • "purple"
  • "blue"
  • "teal"
  • "green"
  • "yellow"
  • "orange"
  • "pink"
  • "red"
iconstring | null

Avatar icon as a prefixed string: emoji:🚀 for a raw emoji, or hi:Rocket01 for a curated hugeicon. Null clears it back to the letter monogram.

At most 64 characters.

startDatestring | null

Format date-time.

endDatestring | null

Format date-time.

Responses

200CampaignMutationResult

The mutation was applied

Response attributes
okbooleanRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
PATCH /api/v1/campaigns/{campaignId}
curl -X PATCH "https://orbitwrite.com/api/v1/campaigns/{campaignId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "string"
}'
Response
{
  "ok": true
}

Delete a campaign#

DELETE/api/v1/campaigns/{campaignId}

Requires campaign:delete. Removes the campaign and everything it generated — its posts (and their approval rows via cascade) and the orphaned per-topic composer groups.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

campaignIdstringRequired

At least 1 character.

Responses

200CampaignMutationResult

The mutation was applied

Response attributes
okbooleanRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
DELETE /api/v1/campaigns/{campaignId}
curl -X DELETE "https://orbitwrite.com/api/v1/campaigns/{campaignId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "ok": true
}

Duplicate a campaign#

POST/api/v1/campaigns/{campaignId}/duplicate

Requires campaign:create. Copies the campaign's own fields (name, description, colour, date range) into a new campaign. Posts are not copied.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

campaignIdstringRequired

At least 1 character.

Responses

200CampaignRefResult

The new campaign

Response attributes
okbooleanRequired
campaignCampaignRefRequired
Child attributes
idstringRequired
titlestring | nullRequired
descriptionstring | nullRequired
colorstringRequired
iconstring | nullRequired
startDatestring | nullRequired
endDatestring | nullRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/campaigns/{campaignId}/duplicate
curl -X POST "https://orbitwrite.com/api/v1/campaigns/{campaignId}/duplicate" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "ok": true,
  "campaign": {
    "id": "string",
    "title": "string",
    "description": "string",
    "color": "string",
    "icon": "string",
    "startDate": "string",
    "endDate": "string"
  }
}

Delete multiple campaigns#

POST/api/v1/campaigns/batch-delete

Requires campaign:delete. Bulk-deletes campaigns owned by the given organization (with their posts and orphaned composer groups). Ids the organization doesn't own are skipped; deletedIds says what was removed.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

idsstring[]Required

Between 1 and 200 items.

Responses

200BatchDeleteCampaignsResult

The ids that were deleted

Response attributes
okbooleanRequired
deletedIdsstring[]Required
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/campaigns/batch-delete
curl -X POST "https://orbitwrite.com/api/v1/campaigns/batch-delete" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "ids": [
    "string"
  ]
}'
Response
{
  "ok": true,
  "deletedIds": [
    "string"
  ]
}

Approve or reject a campaign#

POST/api/v1/campaigns/{campaignId}/decision

Requires approval:decide — green-lighting a campaign is the same authority as approving a post. Approving releases the campaign's still-pending posts into the scheduled queue; rejecting drops them back to Drafts. Creating a campaign takes only campaign:create; deciding one is a separate authority.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

campaignIdstringRequired

At least 1 character.

Body application/json

decisionstringRequired
  • "approved"
  • "rejected"
commentstring | null

At most 1000 characters.

Responses

200CampaignDecisionResult

The decision was recorded

Response attributes
okbooleanRequired
decisionstringRequired
  • "approved"
  • "rejected"
postCountintegerRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
409Error

Conflicts with an existing resource

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/campaigns/{campaignId}/decision
curl -X POST "https://orbitwrite.com/api/v1/campaigns/{campaignId}/decision" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "decision": "approved"
}'
Response
{
  "ok": true,
  "decision": "approved",
  "postCount": 0
}

Generate a campaign's posts from an approved topic plan#

POST/api/v1/campaigns/generate

Requires campaign:create. Fans out AI generation across the selected accounts and persists a campaign with one composer group per topic, each post held in pending_approval until the campaign is approved.

Authentication

A signed-in session only. The Orbitwrite app calls this; an API key is refused.

Body application/json

campaignIdstring | null

Attach the generated posts to this already-created bare campaign instead of minting a new one.

At least 1 character.

titlestring | null

At most 200 characters.

sourcestringRequired

The article URL or free-text brief the campaign promotes.

Between 1 and 4000 characters.

timelineTypestringRequired
  • "date"
  • "evergreen"
targetDatestring | null

Format date-time.

durationstring

At most 40 characters.

accountIdsstring[]Required

At least 1 item.

topicsobject[]Required

Between 1 and 40 items.

Child attributes
scheduledAtstringRequired

Format date-time.

topicstringRequired

Between 1 and 280 characters.

Responses

200GenerateCampaignResult

The campaign and its generated posts were created

Response attributes
okbooleanRequired
campaignIdstringRequired
postCountintegerRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
429Error

Rate limit exceeded

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/campaigns/generate
curl -X POST "https://orbitwrite.com/api/v1/campaigns/generate" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "source": "string",
  "timelineType": "date",
  "accountIds": [
    "string"
  ],
  "topics": [
    {
      "scheduledAt": "2026-10-01T09:00:00Z",
      "topic": "string"
    }
  ]
}'
Response
{
  "ok": true,
  "campaignId": "string",
  "postCount": 0
}