API reference

Auto-DM

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

List Auto-DM campaigns#

GET/api/v1/auto-dms

The workspace's Auto-DM campaigns, newest first, each with its rule, window and send counts. Requires autoDm:read.

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.

statusstring

Comma-separated: active, paused, completed, stopped

accountIdstring
groupIdstring

One post's campaigns — one per channel it went out on.

cursorstring
limitinteger

Between 1 and 100.

Responses

200AutoDmCampaignList

A page of campaigns

Response attributes
campaignsAutoDmCampaign[]Required
Child attributes
idstringRequired
statusstringRequired
  • "active"
  • "paused"
  • "completed"
  • "stopped"
groupIdstring | nullRequired
postIdstringRequired
postTextstringRequired
platformUrlstring | nullRequired
channelobjectRequired
Child attributes
idstringRequired
platformstringRequired
handlestring | nullRequired
displayNamestring | nullRequired
avatarUrlstring | nullRequired
ruleAutoDmRuleRequired
Child attributes
messagestringRequired

The DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.

triggersstring[]Required

What earns the message: reposting the post, replying to it, or both.

  • "repost"
  • "reply"
matchstringRequired

all: every trigger must have happened. any: one is enough.

  • "all"
  • "any"
requireFollowbooleanRequired

Only message people who follow the sending channel.

replyKeywordstring

With the reply trigger, the reply must contain this text (case-insensitive).

durationDaysintegerRequired

How many days after it starts the campaign keeps looking (1–7).

startsAtstringRequired
endsAtstringRequired
lastPolledAtstring | nullRequired
nextPollAtstring | nullRequired
lastErrorstring | nullRequired

Why the last look for engagers or the last send didn't go through (a reconnect needed, a rate limit, the daily cap). Cleared by the next good poll.

completedAtstring | nullRequired
createdAtstringRequired
statsobjectRequired
Child attributes
waitingnumberRequired

Engaged, but haven't met the whole rule yet.

sentnumberRequired
failednumberRequired
dailySendLimitnumberRequired
nextCursorstring | nullRequired

Pass as cursor to fetch the next page; null when exhausted

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/auto-dms
curl -X GET "https://orbitwrite.com/api/v1/auto-dms" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "campaigns": [
    {
      "id": "string",
      "status": "active",
      "groupId": "string",
      "postId": "string",
      "postText": "string",
      "platformUrl": "string",
      "channel": {
        "id": "string",
        "platform": "string",
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "rule": {
        "message": "string",
        "triggers": [
          "repost"
        ],
        "match": "all",
        "requireFollow": true,
        "replyKeyword": "string",
        "durationDays": 0
      },
      "startsAt": "string",
      "endsAt": "string",
      "lastPolledAt": "string",
      "nextPollAt": "string",
      "lastError": "string",
      "completedAt": "string",
      "createdAt": "string",
      "stats": {
        "waiting": 0,
        "sent": 0,
        "failed": 0
      },
      "dailySendLimit": 0
    }
  ],
  "nextCursor": "string"
}

Start an Auto-DM on a published post#

POST/api/v1/auto-dms

For durationDays from now, message everyone who reposts and/or replies to a post that has already been published — including people who engaged before it started. To set one up on a post that hasn't gone out yet, put it on the post instead (autoEngagement.dm on POST /posts) and it starts when the post publishes.

Sent by the channel the post went out on; pass accountId when the post went out on several. Requires autoDm:create and post:publish — nothing reviews a campaign started on a live post, so it takes the same authority as publishing. 409 when the post isn't published yet or already has a campaign.

Authentication

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

Body application/json

messagestring

At most 10000 characters. Defaults to "".

triggersstring[]

At most 2 items. Defaults to ["repost","reply"].

  • "repost"
  • "reply"
matchstring

Defaults to "all".

  • "all"
  • "any"
requireFollowboolean

Defaults to false.

replyKeywordstring

At most 100 characters.

durationDaysinteger

Between 1 and 7. Defaults to 4.

groupIdstringRequired

At least 1 character.

accountIdstring

At least 1 character.

organizationIdstring

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

At least 1 character.

Responses

200AutoDmCampaign

The campaign

Response attributes
idstringRequired
statusstringRequired
  • "active"
  • "paused"
  • "completed"
  • "stopped"
groupIdstring | nullRequired
postIdstringRequired
postTextstringRequired
platformUrlstring | nullRequired
channelobjectRequired
Child attributes
idstringRequired
platformstringRequired
handlestring | nullRequired
displayNamestring | nullRequired
avatarUrlstring | nullRequired
ruleAutoDmRuleRequired
Child attributes
messagestringRequired

The DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.

triggersstring[]Required

What earns the message: reposting the post, replying to it, or both.

  • "repost"
  • "reply"
matchstringRequired

all: every trigger must have happened. any: one is enough.

  • "all"
  • "any"
requireFollowbooleanRequired

Only message people who follow the sending channel.

replyKeywordstring

With the reply trigger, the reply must contain this text (case-insensitive).

durationDaysintegerRequired

How many days after it starts the campaign keeps looking (1–7).

startsAtstringRequired
endsAtstringRequired
lastPolledAtstring | nullRequired
nextPollAtstring | nullRequired
lastErrorstring | nullRequired

Why the last look for engagers or the last send didn't go through (a reconnect needed, a rate limit, the daily cap). Cleared by the next good poll.

completedAtstring | nullRequired
createdAtstringRequired
statsobjectRequired
Child attributes
waitingnumberRequired

Engaged, but haven't met the whole rule yet.

sentnumberRequired
failednumberRequired
dailySendLimitnumberRequired
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/auto-dms
curl -X POST "https://orbitwrite.com/api/v1/auto-dms" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "groupId": "string"
}'
Response
{
  "id": "string",
  "status": "active",
  "groupId": "string",
  "postId": "string",
  "postText": "string",
  "platformUrl": "string",
  "channel": {
    "id": "string",
    "platform": "string",
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "rule": {
    "message": "string",
    "triggers": [
      "repost"
    ],
    "match": "all",
    "requireFollow": true,
    "replyKeyword": "string",
    "durationDays": 0
  },
  "startsAt": "string",
  "endsAt": "string",
  "lastPolledAt": "string",
  "nextPollAt": "string",
  "lastError": "string",
  "completedAt": "string",
  "createdAt": "string",
  "stats": {
    "waiting": 0,
    "sent": 0,
    "failed": 0
  },
  "dailySendLimit": 0
}

Which channels can send Auto-DMs#

GET/api/v1/auto-dms/channels

Every connected channel on a platform that supports Auto-DM (Bluesky, Mastodon), with whether it can send as connected today. needs_reconnect means the connection predates the direct-message permission — reconnecting the channel grants it. Also carries each platform's message length and daily send limit. Requires autoDm:read and account:read.

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

200AutoDmChannelList

The workspace's Auto-DM-capable channels

Response attributes
channelsAutoDmChannel[]Required
Child attributes
accountIdstringRequired
platformstringRequired
  • "bluesky"
  • "mastodon"
handlestring | nullRequired
avatarUrlstring | nullRequired
statusstringRequired
  • "ready"
  • "unsupported"
  • "needs_reconnect"
reasonstring
maxMessageCharsnumberRequired
dailySendLimitnumberRequired
repostLabelstringRequired
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/auto-dms/channels
curl -X GET "https://orbitwrite.com/api/v1/auto-dms/channels" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "channels": [
    {
      "accountId": "string",
      "platform": "bluesky",
      "handle": "string",
      "avatarUrl": "string",
      "status": "ready",
      "reason": "string",
      "maxMessageChars": 0,
      "dailySendLimit": 0,
      "repostLabel": "string"
    }
  ]
}

Who an Auto-DM campaign has seen and messaged#

GET/api/v1/auto-dms/{campaignId}/recipients

Everyone who engaged with the post, newest first: sent (with the message as it went out), failed (with why — usually the person doesn't accept DMs), waiting (engaged but hasn't met the whole rule yet) and sending (in flight). Requires autoDm:read.

Authentication

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

Path parameters

campaignIdstringRequired

At least 1 character.

Query parameters

organizationIdstring

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

At least 1 character.

statusstring

Comma-separated: waiting, sending, sent, failed

cursorstring
limitinteger

Between 1 and 200.

Responses

200AutoDmRecipientList

A page of recipients

Response attributes
recipientsAutoDmRecipient[]Required
Child attributes
idstringRequired
platformUserIdstringRequired
handlestringRequired
displayNamestring | nullRequired
avatarUrlstring | nullRequired
statusstringRequired
  • "waiting"
  • "sending"
  • "sent"
  • "failed"
repostedbooleanRequired
repliedbooleanRequired
followsboolean | nullRequired
messagestring | nullRequired
errorstring | nullRequired
sentAtstring | nullRequired
firstSeenAtstringRequired
nextCursorstring | 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[]
GET /api/v1/auto-dms/{campaignId}/recipients
curl -X GET "https://orbitwrite.com/api/v1/auto-dms/{campaignId}/recipients" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "recipients": [
    {
      "id": "string",
      "platformUserId": "string",
      "handle": "string",
      "displayName": "string",
      "avatarUrl": "string",
      "status": "waiting",
      "reposted": true,
      "replied": true,
      "follows": true,
      "message": "string",
      "error": "string",
      "sentAt": "string",
      "firstSeenAt": "string"
    }
  ],
  "nextCursor": "string"
}

Stop an Auto-DM campaign for good#

POST/api/v1/auto-dms/{campaignId}/stop

Nothing more is sent. The campaign and its recipients stay readable. Idempotent — stopping a finished campaign returns it unchanged. Requires autoDm:delete.

Authentication

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

Path parameters

campaignIdstringRequired

At least 1 character.

Query parameters

organizationIdstring

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

At least 1 character.

Responses

200AutoDmCampaign

The campaign

Response attributes
idstringRequired
statusstringRequired
  • "active"
  • "paused"
  • "completed"
  • "stopped"
groupIdstring | nullRequired
postIdstringRequired
postTextstringRequired
platformUrlstring | nullRequired
channelobjectRequired
Child attributes
idstringRequired
platformstringRequired
handlestring | nullRequired
displayNamestring | nullRequired
avatarUrlstring | nullRequired
ruleAutoDmRuleRequired
Child attributes
messagestringRequired

The DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.

triggersstring[]Required

What earns the message: reposting the post, replying to it, or both.

  • "repost"
  • "reply"
matchstringRequired

all: every trigger must have happened. any: one is enough.

  • "all"
  • "any"
requireFollowbooleanRequired

Only message people who follow the sending channel.

replyKeywordstring

With the reply trigger, the reply must contain this text (case-insensitive).

durationDaysintegerRequired

How many days after it starts the campaign keeps looking (1–7).

startsAtstringRequired
endsAtstringRequired
lastPolledAtstring | nullRequired
nextPollAtstring | nullRequired
lastErrorstring | nullRequired

Why the last look for engagers or the last send didn't go through (a reconnect needed, a rate limit, the daily cap). Cleared by the next good poll.

completedAtstring | nullRequired
createdAtstringRequired
statsobjectRequired
Child attributes
waitingnumberRequired

Engaged, but haven't met the whole rule yet.

sentnumberRequired
failednumberRequired
dailySendLimitnumberRequired
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/auto-dms/{campaignId}/stop
curl -X POST "https://orbitwrite.com/api/v1/auto-dms/{campaignId}/stop" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "id": "string",
  "status": "active",
  "groupId": "string",
  "postId": "string",
  "postText": "string",
  "platformUrl": "string",
  "channel": {
    "id": "string",
    "platform": "string",
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "rule": {
    "message": "string",
    "triggers": [
      "repost"
    ],
    "match": "all",
    "requireFollow": true,
    "replyKeyword": "string",
    "durationDays": 0
  },
  "startsAt": "string",
  "endsAt": "string",
  "lastPolledAt": "string",
  "nextPollAt": "string",
  "lastError": "string",
  "completedAt": "string",
  "createdAt": "string",
  "stats": {
    "waiting": 0,
    "sent": 0,
    "failed": 0
  },
  "dailySendLimit": 0
}

Read one Auto-DM campaign#

GET/api/v1/auto-dms/{campaignId}

Its rule, window, status and send counts. Requires autoDm:read.

Authentication

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

Path parameters

campaignIdstringRequired

At least 1 character.

Query parameters

organizationIdstring

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

At least 1 character.

Responses

200AutoDmCampaign

The campaign

Response attributes
idstringRequired
statusstringRequired
  • "active"
  • "paused"
  • "completed"
  • "stopped"
groupIdstring | nullRequired
postIdstringRequired
postTextstringRequired
platformUrlstring | nullRequired
channelobjectRequired
Child attributes
idstringRequired
platformstringRequired
handlestring | nullRequired
displayNamestring | nullRequired
avatarUrlstring | nullRequired
ruleAutoDmRuleRequired
Child attributes
messagestringRequired

The DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.

triggersstring[]Required

What earns the message: reposting the post, replying to it, or both.

  • "repost"
  • "reply"
matchstringRequired

all: every trigger must have happened. any: one is enough.

  • "all"
  • "any"
requireFollowbooleanRequired

Only message people who follow the sending channel.

replyKeywordstring

With the reply trigger, the reply must contain this text (case-insensitive).

durationDaysintegerRequired

How many days after it starts the campaign keeps looking (1–7).

startsAtstringRequired
endsAtstringRequired
lastPolledAtstring | nullRequired
nextPollAtstring | nullRequired
lastErrorstring | nullRequired

Why the last look for engagers or the last send didn't go through (a reconnect needed, a rate limit, the daily cap). Cleared by the next good poll.

completedAtstring | nullRequired
createdAtstringRequired
statsobjectRequired
Child attributes
waitingnumberRequired

Engaged, but haven't met the whole rule yet.

sentnumberRequired
failednumberRequired
dailySendLimitnumberRequired
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[]
GET /api/v1/auto-dms/{campaignId}
curl -X GET "https://orbitwrite.com/api/v1/auto-dms/{campaignId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "id": "string",
  "status": "active",
  "groupId": "string",
  "postId": "string",
  "postText": "string",
  "platformUrl": "string",
  "channel": {
    "id": "string",
    "platform": "string",
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "rule": {
    "message": "string",
    "triggers": [
      "repost"
    ],
    "match": "all",
    "requireFollow": true,
    "replyKeyword": "string",
    "durationDays": 0
  },
  "startsAt": "string",
  "endsAt": "string",
  "lastPolledAt": "string",
  "nextPollAt": "string",
  "lastError": "string",
  "completedAt": "string",
  "createdAt": "string",
  "stats": {
    "waiting": 0,
    "sent": 0,
    "failed": 0
  },
  "dailySendLimit": 0
}

Pause, resume or change an Auto-DM campaign#

PATCH/api/v1/auto-dms/{campaignId}

status: "paused" stops sending until status: "active" resumes it. Rule fields you send replace the stored ones and apply to the next send — nobody already messaged is messaged again. durationDays is measured from the campaign's start. Requires autoDm:update. 409 once the campaign has finished or been stopped.

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

statusstring
  • "active"
  • "paused"
messagestring

At most 10000 characters.

triggersstring[]

Between 1 and 2 items.

  • "repost"
  • "reply"
matchstring
  • "all"
  • "any"
replyKeywordstring | null

At most 100 characters.

durationDaysinteger

Between 1 and 7.

organizationIdstring

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

At least 1 character.

Responses

200AutoDmCampaign

The campaign

Response attributes
idstringRequired
statusstringRequired
  • "active"
  • "paused"
  • "completed"
  • "stopped"
groupIdstring | nullRequired
postIdstringRequired
postTextstringRequired
platformUrlstring | nullRequired
channelobjectRequired
Child attributes
idstringRequired
platformstringRequired
handlestring | nullRequired
displayNamestring | nullRequired
avatarUrlstring | nullRequired
ruleAutoDmRuleRequired
Child attributes
messagestringRequired

The DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.

triggersstring[]Required

What earns the message: reposting the post, replying to it, or both.

  • "repost"
  • "reply"
matchstringRequired

all: every trigger must have happened. any: one is enough.

  • "all"
  • "any"
requireFollowbooleanRequired

Only message people who follow the sending channel.

replyKeywordstring

With the reply trigger, the reply must contain this text (case-insensitive).

durationDaysintegerRequired

How many days after it starts the campaign keeps looking (1–7).

startsAtstringRequired
endsAtstringRequired
lastPolledAtstring | nullRequired
nextPollAtstring | nullRequired
lastErrorstring | nullRequired

Why the last look for engagers or the last send didn't go through (a reconnect needed, a rate limit, the daily cap). Cleared by the next good poll.

completedAtstring | nullRequired
createdAtstringRequired
statsobjectRequired
Child attributes
waitingnumberRequired

Engaged, but haven't met the whole rule yet.

sentnumberRequired
failednumberRequired
dailySendLimitnumberRequired
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[]
PATCH /api/v1/auto-dms/{campaignId}
curl -X PATCH "https://orbitwrite.com/api/v1/auto-dms/{campaignId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "active",
  "message": "string",
  "triggers": [
    "repost"
  ],
  "match": "all",
  "requireFollow": true,
  "replyKeyword": "string",
  "durationDays": 1,
  "organizationId": "string"
}'
Response
{
  "id": "string",
  "status": "active",
  "groupId": "string",
  "postId": "string",
  "postText": "string",
  "platformUrl": "string",
  "channel": {
    "id": "string",
    "platform": "string",
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "rule": {
    "message": "string",
    "triggers": [
      "repost"
    ],
    "match": "all",
    "requireFollow": true,
    "replyKeyword": "string",
    "durationDays": 0
  },
  "startsAt": "string",
  "endsAt": "string",
  "lastPolledAt": "string",
  "nextPollAt": "string",
  "lastError": "string",
  "completedAt": "string",
  "createdAt": "string",
  "stats": {
    "waiting": 0,
    "sent": 0,
    "failed": 0
  },
  "dailySendLimit": 0
}