API reference
7 endpoints, served at https://orbitwrite.com/api/v1. Each one lists the credentials it accepts, its parameters and every response it can give.
The workspace's Auto-DM campaigns, newest first, each with its rule, window and send counts. Requires autoDm:read.
An API key or OAuth access token as a bearer token, or a signed-in session.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
statusstringComma-separated: active, paused, completed, stopped
accountIdstringgroupIdstringOne post's campaigns — one per channel it went out on.
cursorstringlimitintegerBetween 1 and 100.
200AutoDmCampaignListA page of campaigns
campaignsAutoDmCampaign[]RequiredidstringRequiredstatusstringRequired"active""paused""completed""stopped"groupIdstring | nullRequiredpostIdstringRequiredpostTextstringRequiredplatformUrlstring | nullRequiredchannelobjectRequiredidstringRequiredplatformstringRequiredhandlestring | nullRequireddisplayNamestring | nullRequiredavatarUrlstring | nullRequiredruleAutoDmRuleRequiredmessagestringRequiredThe DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.
triggersstring[]RequiredWhat earns the message: reposting the post, replying to it, or both.
"repost""reply"matchstringRequiredall: every trigger must have happened. any: one is enough.
"all""any"requireFollowbooleanRequiredOnly message people who follow the sending channel.
replyKeywordstringWith the reply trigger, the reply must contain this text (case-insensitive).
durationDaysintegerRequiredHow many days after it starts the campaign keeps looking (1–7).
startsAtstringRequiredendsAtstringRequiredlastPolledAtstring | nullRequirednextPollAtstring | nullRequiredlastErrorstring | nullRequiredWhy 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 | nullRequiredcreatedAtstringRequiredstatsobjectRequireddailySendLimitnumberRequirednextCursorstring | nullRequiredPass as cursor to fetch the next page; null when exhausted
curl -X GET "https://orbitwrite.com/api/v1/auto-dms" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"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"
}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.
An API key or OAuth access token as a bearer token, or a signed-in session.
messagestringAt most 10000 characters. Defaults to "".
triggersstring[]At most 2 items. Defaults to ["repost","reply"].
"repost""reply"matchstringDefaults to "all".
"all""any"requireFollowbooleanDefaults to false.
replyKeywordstringAt most 100 characters.
durationDaysintegerBetween 1 and 7. Defaults to 4.
groupIdstringRequiredAt least 1 character.
accountIdstringAt least 1 character.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
200AutoDmCampaignThe campaign
idstringRequiredstatusstringRequired"active""paused""completed""stopped"groupIdstring | nullRequiredpostIdstringRequiredpostTextstringRequiredplatformUrlstring | nullRequiredchannelobjectRequiredidstringRequiredplatformstringRequiredhandlestring | nullRequireddisplayNamestring | nullRequiredavatarUrlstring | nullRequiredruleAutoDmRuleRequiredmessagestringRequiredThe DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.
triggersstring[]RequiredWhat earns the message: reposting the post, replying to it, or both.
"repost""reply"matchstringRequiredall: every trigger must have happened. any: one is enough.
"all""any"requireFollowbooleanRequiredOnly message people who follow the sending channel.
replyKeywordstringWith the reply trigger, the reply must contain this text (case-insensitive).
durationDaysintegerRequiredHow many days after it starts the campaign keeps looking (1–7).
startsAtstringRequiredendsAtstringRequiredlastPolledAtstring | nullRequirednextPollAtstring | nullRequiredlastErrorstring | nullRequiredWhy 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 | nullRequiredcreatedAtstringRequiredstatsobjectRequireddailySendLimitnumberRequiredcurl -X POST "https://orbitwrite.com/api/v1/auto-dms" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"groupId": "string"
}'{
"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
}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.
An API key or OAuth access token as a bearer token, or a signed-in session.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
200AutoDmChannelListThe workspace's Auto-DM-capable channels
channelsAutoDmChannel[]RequiredaccountIdstringRequiredplatformstringRequired"bluesky""mastodon"handlestring | nullRequiredavatarUrlstring | nullRequiredstatusstringRequired"ready""unsupported""needs_reconnect"reasonstringmaxMessageCharsnumberRequireddailySendLimitnumberRequiredrepostLabelstringRequiredcurl -X GET "https://orbitwrite.com/api/v1/auto-dms/channels" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"channels": [
{
"accountId": "string",
"platform": "bluesky",
"handle": "string",
"avatarUrl": "string",
"status": "ready",
"reason": "string",
"maxMessageChars": 0,
"dailySendLimit": 0,
"repostLabel": "string"
}
]
}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.
An API key or OAuth access token as a bearer token, or a signed-in session.
campaignIdstringRequiredAt least 1 character.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
statusstringComma-separated: waiting, sending, sent, failed
cursorstringlimitintegerBetween 1 and 200.
200AutoDmRecipientListA page of recipients
recipientsAutoDmRecipient[]RequiredidstringRequiredplatformUserIdstringRequiredhandlestringRequireddisplayNamestring | nullRequiredavatarUrlstring | nullRequiredstatusstringRequired"waiting""sending""sent""failed"repostedbooleanRequiredrepliedbooleanRequiredfollowsboolean | nullRequiredmessagestring | nullRequirederrorstring | nullRequiredsentAtstring | nullRequiredfirstSeenAtstringRequirednextCursorstring | nullRequiredcurl -X GET "https://orbitwrite.com/api/v1/auto-dms/{campaignId}/recipients" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"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"
}Nothing more is sent. The campaign and its recipients stay readable. Idempotent — stopping a finished campaign returns it unchanged. Requires autoDm:delete.
An API key or OAuth access token as a bearer token, or a signed-in session.
campaignIdstringRequiredAt least 1 character.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
200AutoDmCampaignThe campaign
idstringRequiredstatusstringRequired"active""paused""completed""stopped"groupIdstring | nullRequiredpostIdstringRequiredpostTextstringRequiredplatformUrlstring | nullRequiredchannelobjectRequiredidstringRequiredplatformstringRequiredhandlestring | nullRequireddisplayNamestring | nullRequiredavatarUrlstring | nullRequiredruleAutoDmRuleRequiredmessagestringRequiredThe DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.
triggersstring[]RequiredWhat earns the message: reposting the post, replying to it, or both.
"repost""reply"matchstringRequiredall: every trigger must have happened. any: one is enough.
"all""any"requireFollowbooleanRequiredOnly message people who follow the sending channel.
replyKeywordstringWith the reply trigger, the reply must contain this text (case-insensitive).
durationDaysintegerRequiredHow many days after it starts the campaign keeps looking (1–7).
startsAtstringRequiredendsAtstringRequiredlastPolledAtstring | nullRequirednextPollAtstring | nullRequiredlastErrorstring | nullRequiredWhy 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 | nullRequiredcreatedAtstringRequiredstatsobjectRequireddailySendLimitnumberRequiredcurl -X POST "https://orbitwrite.com/api/v1/auto-dms/{campaignId}/stop" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"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
}Its rule, window, status and send counts. Requires autoDm:read.
An API key or OAuth access token as a bearer token, or a signed-in session.
campaignIdstringRequiredAt least 1 character.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
200AutoDmCampaignThe campaign
idstringRequiredstatusstringRequired"active""paused""completed""stopped"groupIdstring | nullRequiredpostIdstringRequiredpostTextstringRequiredplatformUrlstring | nullRequiredchannelobjectRequiredidstringRequiredplatformstringRequiredhandlestring | nullRequireddisplayNamestring | nullRequiredavatarUrlstring | nullRequiredruleAutoDmRuleRequiredmessagestringRequiredThe DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.
triggersstring[]RequiredWhat earns the message: reposting the post, replying to it, or both.
"repost""reply"matchstringRequiredall: every trigger must have happened. any: one is enough.
"all""any"requireFollowbooleanRequiredOnly message people who follow the sending channel.
replyKeywordstringWith the reply trigger, the reply must contain this text (case-insensitive).
durationDaysintegerRequiredHow many days after it starts the campaign keeps looking (1–7).
startsAtstringRequiredendsAtstringRequiredlastPolledAtstring | nullRequirednextPollAtstring | nullRequiredlastErrorstring | nullRequiredWhy 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 | nullRequiredcreatedAtstringRequiredstatsobjectRequireddailySendLimitnumberRequiredcurl -X GET "https://orbitwrite.com/api/v1/auto-dms/{campaignId}" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"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
}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.
An API key or OAuth access token as a bearer token, or a signed-in session.
campaignIdstringRequiredAt least 1 character.
statusstring"active""paused"messagestringAt most 10000 characters.
triggersstring[]Between 1 and 2 items.
"repost""reply"matchstring"all""any"requireFollowbooleanreplyKeywordstring | nullAt most 100 characters.
durationDaysintegerBetween 1 and 7.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
200AutoDmCampaignThe campaign
idstringRequiredstatusstringRequired"active""paused""completed""stopped"groupIdstring | nullRequiredpostIdstringRequiredpostTextstringRequiredplatformUrlstring | nullRequiredchannelobjectRequiredidstringRequiredplatformstringRequiredhandlestring | nullRequireddisplayNamestring | nullRequiredavatarUrlstring | nullRequiredruleAutoDmRuleRequiredmessagestringRequiredThe DM. {first_name} (first name), {name} (full name), {username} (username), {action} (action), {post_url} (post url) are filled in per recipient.
triggersstring[]RequiredWhat earns the message: reposting the post, replying to it, or both.
"repost""reply"matchstringRequiredall: every trigger must have happened. any: one is enough.
"all""any"requireFollowbooleanRequiredOnly message people who follow the sending channel.
replyKeywordstringWith the reply trigger, the reply must contain this text (case-insensitive).
durationDaysintegerRequiredHow many days after it starts the campaign keeps looking (1–7).
startsAtstringRequiredendsAtstringRequiredlastPolledAtstring | nullRequirednextPollAtstring | nullRequiredlastErrorstring | nullRequiredWhy 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 | nullRequiredcreatedAtstringRequiredstatsobjectRequireddailySendLimitnumberRequiredcurl -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"
}'{
"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
}