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.
/api/v1/integrations/discord/install-urlGET/api/v1/integrations/discordPOST/api/v1/integrations/discord/channelsGET/api/v1/integrations/discord/guilds/{guildId}/channelsPOST/api/v1/integrations/discord/routesPOST/api/v1/integrations/discord/routes/{routeId}/toggleDEL/api/v1/integrations/discord/routes/{routeId}Returns the Discord authorization URL a server owner must open to add the bot. This step cannot be performed over an API — Discord requires a human to choose the server — so the URL is what an API caller gets. The picker that callback leads to connects the first channel, which is what binds the server to this workspace; after that GET /integrations/discord/guilds/{guildId}/channels and POST /integrations/discord/channels are both headless. Requires integration:connect.
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.
200DiscordInstallUrlThe install URL
urlstringRequiredpermissionsstringRequiredThe Discord permissions bitmask the install requests.
curl -X GET "https://orbitwrite.com/api/v1/integrations/discord/install-url" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"url": "string",
"permissions": "string"
}Returns the connected guild(s), the notification routes, the channels the bot can post to, and the workspace's tags for the optional tag filter. Requires integration:read, which every role holds. Channel listing failures degrade to an empty list.
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.
200DiscordIntegrationThe workspace's Discord integration state
routesDiscordNotificationRoute[]Requiredcurl -X GET "https://orbitwrite.com/api/v1/integrations/discord" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"guilds": [
{
"guildId": "string",
"guildName": "string"
}
],
"routes": [
{
"id": "string",
"guildId": "string",
"guildName": "string",
"channelId": "string",
"channelName": "string",
"events": [
"post_published"
],
"tagId": "string",
"enabled": true
}
],
"channels": [
{
"id": "string",
"name": "string",
"guildId": "string"
}
],
"tags": [
{
"id": "string",
"name": "string",
"color": "string"
}
]
}Adds a Discord channel to the workspace's channels, so posts can be published to it. The server must be one this workspace has already connected — Discord's bot token is shared across tenants, so an unscoped guildId would let any workspace attach another's channel and publish into it. Connecting a server for the first time therefore runs through the browser: GET /integrations/discord/install-url returns the URL, and the picker it leads to connects the first channel. Every channel after that is reachable from here. Requires account:connect.
An API key or OAuth access token as a bearer token, or a signed-in session.
organizationIdstringRequired for session callers with no active organization. Optional for an API key, which is already scoped to one workspace — but a key naming a *different* workspace is refused with 403 rather than having the field ignored, so a caller can never believe it wrote somewhere it didn't.
At least 1 character.
guildIdstringRequiredThe server the channel belongs to. Checked twice: that this workspace has connected it (404 otherwise, whether or not it exists), and that the channel really is in it.
At least 1 character.
channelIdstringRequiredA Discord channel id. Its name, and the server's, are read from Discord rather than from this request.
At least 1 character.
200ConnectDiscordChannelResultThe channel is connected
okbooleanRequiredchannelConnectedDiscordChannelRequiredidstringRequireddisplayHandlestringRequiredcreatedbooleanRequiredrestoredbooleanRequiredbecamePrimarybooleanRequiredcurl -X POST "https://orbitwrite.com/api/v1/integrations/discord/channels" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"guildId": "string",
"channelId": "string"
}'{
"ok": true,
"channel": {
"id": "string",
"displayHandle": "string",
"created": true,
"restored": true,
"becamePrimary": true
}
}The text and announcement channels the bot can see in a server this workspace has already connected. Use it to pick a channel for POST /integrations/discord/channels. A server the workspace has not connected answers 404, whether or not it exists — the bot token is shared across tenants, so an unscoped lookup here would expose another workspace's channel names. The first channel in a new server is connected through the browser picker the install URL leads to. Requires integration:connect.
An API key or OAuth access token as a bearer token, or a signed-in session.
guildIdstringRequiredAt least 1 character.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
200DiscordGuildChannelsThe guild's postable channels
curl -X GET "https://orbitwrite.com/api/v1/integrations/discord/guilds/{guildId}/channels" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"channels": [
{
"id": "string",
"name": "string",
"guildId": "string"
}
]
}Routes the chosen events (optionally filtered by tag) to a Discord channel. The channel is resolved server-side against what the bot can see — the guild comes from the channel, not from the request. Requires integration:update.
An API key or OAuth access token as a bearer token, or a signed-in session.
organizationIdstringRequired for session callers with no active organization. Optional for an API key, which is already scoped to one workspace — but a key naming a *different* workspace is refused with 403 rather than having the field ignored, so a caller can never believe it wrote somewhere it didn't.
At least 1 character.
channelIdstringRequiredAt least 1 character.
eventsstring[]RequiredAt least 1 item.
"post_published""post_failed""approval_requested""approval_decided""account_needs_reconnect""daily_digest"tagIdstring | nullNarrow the rule to posts carrying this tag. Null (or omitted) means all posts; a tag from another workspace is rejected.
curl -X POST "https://orbitwrite.com/api/v1/integrations/discord/routes" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelId": "string",
"events": [
"post_published"
]
}'{
"ok": true,
"route": {
"id": "string",
"guildId": "string",
"guildName": "string",
"channelId": "string",
"channelName": "string",
"events": [
"post_published"
],
"tagId": "string",
"enabled": true
}
}Requires integration:update.
An API key or OAuth access token as a bearer token, or a signed-in session.
routeIdstringRequiredAt least 1 character.
organizationIdstringRequired for session callers with no active organization. Optional for an API key, which is already scoped to one workspace — but a key naming a *different* workspace is refused with 403 rather than having the field ignored, so a caller can never believe it wrote somewhere it didn't.
At least 1 character.
enabledbooleanRequired200DiscordIntegrationMutationResultThe mutation was applied
okbooleanRequiredcurl -X POST "https://orbitwrite.com/api/v1/integrations/discord/routes/{routeId}/toggle" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true
}'{
"ok": true
}Requires integration:update.
An API key or OAuth access token as a bearer token, or a signed-in session.
routeIdstringRequiredAt least 1 character.
organizationIdstringSession callers only — an API key already determines the workspace.
At least 1 character.
200DiscordIntegrationMutationResultThe mutation was applied
okbooleanRequiredcurl -X DELETE "https://orbitwrite.com/api/v1/integrations/discord/routes/{routeId}" \
-H "Authorization: Bearer $ORBITWRITE_API_KEY"{
"ok": true
}