API reference

Discord

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 browser URL that invites the bot to a Discord server#

GET/api/v1/integrations/discord/install-url

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.

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

200DiscordInstallUrl

The install URL

Response attributes
urlstringRequired
permissionsstringRequired

The Discord permissions bitmask the install requests.

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[]
501Error

Discord OAuth is not configured on this deployment

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/integrations/discord/install-url
curl -X GET "https://orbitwrite.com/api/v1/integrations/discord/install-url" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "url": "string",
  "permissions": "string"
}

Read a workspace's Discord integration#

GET/api/v1/integrations/discord

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.

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

200DiscordIntegration

The workspace's Discord integration state

Response attributes
guildsobject[]Required
Child attributes
guildIdstringRequired
guildNamestring | nullRequired
routesDiscordNotificationRoute[]Required
Child attributes
idstringRequired
guildIdstringRequired
guildNamestring | nullRequired
channelIdstringRequired
channelNamestring | nullRequired
eventsstring[]Required
  • "post_published"
  • "post_failed"
  • "approval_requested"
  • "approval_decided"
  • "account_needs_reconnect"
  • "daily_digest"
tagIdstring | nullRequired
enabledbooleanRequired
channelsobject[]Required
Child attributes
idstringRequired
namestringRequired
guildIdstringRequired
tagsobject[]Required
Child attributes
idstringRequired
namestringRequired
colorstringRequired
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/integrations/discord
curl -X GET "https://orbitwrite.com/api/v1/integrations/discord" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "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"
    }
  ]
}

Connect a Discord channel as a posting channel#

POST/api/v1/integrations/discord/channels

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.

Authentication

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

Body application/json

organizationIdstring

Required 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.

guildIdstringRequired

The 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.

channelIdstringRequired

A Discord channel id. Its name, and the server's, are read from Discord rather than from this request.

At least 1 character.

Responses

200ConnectDiscordChannelResult

The channel is connected

Response attributes
okbooleanRequired
channelConnectedDiscordChannelRequired
Child attributes
idstringRequired
displayHandlestringRequired
createdbooleanRequired
restoredbooleanRequired
becamePrimarybooleanRequired
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[]
502Error

Discord API unreachable while verifying the channel

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/integrations/discord/channels
curl -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"
}'
Response
{
  "ok": true,
  "channel": {
    "id": "string",
    "displayHandle": "string",
    "created": true,
    "restored": true,
    "becamePrimary": true
  }
}

List the postable channels in a Discord server#

GET/api/v1/integrations/discord/guilds/{guildId}/channels

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.

Authentication

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

Path parameters

guildIdstringRequired

At least 1 character.

Query parameters

organizationIdstring

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

At least 1 character.

Responses

200DiscordGuildChannels

The guild's postable channels

Response attributes
channelsobject[]Required
Child attributes
idstringRequired
namestringRequired
guildIdstringRequired
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[]
502Error

Discord API unreachable while listing the channels

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/integrations/discord/guilds/{guildId}/channels
curl -X GET "https://orbitwrite.com/api/v1/integrations/discord/guilds/{guildId}/channels" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "channels": [
    {
      "id": "string",
      "name": "string",
      "guildId": "string"
    }
  ]
}

Add a notification route#

POST/api/v1/integrations/discord/routes

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.

Authentication

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

Body application/json

organizationIdstring

Required 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.

channelIdstringRequired

At least 1 character.

eventsstring[]Required

At least 1 item.

  • "post_published"
  • "post_failed"
  • "approval_requested"
  • "approval_decided"
  • "account_needs_reconnect"
  • "daily_digest"
tagIdstring | null

Narrow the rule to posts carrying this tag. Null (or omitted) means all posts; a tag from another workspace is rejected.

Responses

200DiscordNotificationRouteResult

The route was added

Response attributes
okbooleanRequired
routeDiscordNotificationRouteRequired
Child attributes
idstringRequired
guildIdstringRequired
guildNamestring | nullRequired
channelIdstringRequired
channelNamestring | nullRequired
eventsstring[]Required
  • "post_published"
  • "post_failed"
  • "approval_requested"
  • "approval_decided"
  • "account_needs_reconnect"
  • "daily_digest"
tagIdstring | nullRequired
enabledbooleanRequired
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[]
502Error

Discord API unreachable while verifying the channel

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/integrations/discord/routes
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"
  ]
}'
Response
{
  "ok": true,
  "route": {
    "id": "string",
    "guildId": "string",
    "guildName": "string",
    "channelId": "string",
    "channelName": "string",
    "events": [
      "post_published"
    ],
    "tagId": "string",
    "enabled": true
  }
}

Enable or pause a notification route#

POST/api/v1/integrations/discord/routes/{routeId}/toggle

Requires integration:update.

Authentication

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

Path parameters

routeIdstringRequired

At least 1 character.

Body application/json

organizationIdstring

Required 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.

enabledbooleanRequired

Responses

200DiscordIntegrationMutationResult

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[]
POST /api/v1/integrations/discord/routes/{routeId}/toggle
curl -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
}'
Response
{
  "ok": true
}

Remove a notification route#

DELETE/api/v1/integrations/discord/routes/{routeId}

Requires integration:update.

Authentication

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

Path parameters

routeIdstringRequired

At least 1 character.

Query parameters

organizationIdstring

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

At least 1 character.

Responses

200DiscordIntegrationMutationResult

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/integrations/discord/routes/{routeId}
curl -X DELETE "https://orbitwrite.com/api/v1/integrations/discord/routes/{routeId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "ok": true
}