Zernio
APIFor you
Zernio
APIFor you
Platforms

Discord

Overview

Set up

Connect

Publish

PublishPlatform Fields & Media

Engage

Inbox

Manage

Server Management

Reference

Limits & Errors
Dashboard
OverviewPlatformsAPI ReferenceResources
Discord

Server Management

Manage channels, roles, members, pinned messages and scheduled events in the bot's Discord server.


The bot administers the server it is installed in: channels, roles, members, pinned messages and scheduled events.

Every call takes accountId as a query parameter and the server's guildId or channelId in the path.

Channels

List the channels in the connected server with GET /v1/accounts/{accountId}/discord-channels (List Discord channels):

const { data: channels } = await zernio.discord.getDiscordChannels({
  path: { accountId: '66b2e19d8c3f5a7e9d0b1c2d' }
});

console.log(channels.channels);

Response (200):

{
  "channels": [
    { "id": "1234567890123456789", "name": "announcements", "type": 5 },
    { "id": "1122334455667788990", "name": "community", "type": 15 }
  ]
}

To move the account to another channel in the same server, send channelId to the same PATCH /v1/accounts/{accountId}/discord-settings call as Webhook identity.

The response carries the account with its new channelId and channelName.

Only text (0), announcement (5) and forum (15) channels are accepted. Zernio creates a new webhook in the target channel.

Roles and members

Nine endpoints cover roles and members. The paths mirror Discord's own API.

  • Roles: list, create, edit and delete.
  • Members: list, search and get.
  • Member roles: assign and remove a role per member.

List every role in a server:

curl "https://zernio.com/api/v1/discord/guilds/1098765432109876543/roles?accountId=66b2e19d8c3f5a7e9d0b1c2d" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200):

{
  "data": [
    {
      "id": "3344556677889900112",
      "name": "Members",
      "color": 3447003,
      "position": 3,
      "permissions": "1071698660929",
      "managed": false,
      "mentionable": true,
      "hoist": false
    }
  ]
}
  • color is a decimal value (0 means no color).
  • permissions is a bitfield as a string.
  • position is the place in the hierarchy, where higher means more authority.
  • managed is true for roles an integration owns, which no one can assign.

List members, cursor-paginated, 100 per page by default and at most 1,000:

curl "https://zernio.com/api/v1/discord/guilds/1098765432109876543/members?accountId=66b2e19d8c3f5a7e9d0b1c2d&limit=100" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200):

{
  "data": [
    {
      "user": { "id": "2233445566778899001", "username": "sam", "global_name": "Sam" },
      "nick": null,
      "roles": ["3344556677889900112"],
      "joined_at": "2026-01-15T10:30:00.000Z"
    }
  ],
  "pagination": { "nextCursor": "2233445566778899001", "hasMore": true }
}

Pass nextCursor as after on the next call until hasMore is false.

This endpoint needs the Server Members Intent on Zernio's Discord app, which is on for new bot installs. An empty array with no error means the intent is missing.

Assign a role to a member:

curl -X PUT "https://zernio.com/api/v1/discord/guilds/1098765432109876543/members/2233445566778899001/roles/3344556677889900112?accountId=66b2e19d8c3f5a7e9d0b1c2d" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200):

{
  "success": true,
  "operation": "role_assigned",
  "guildId": "1098765432109876543",
  "userId": "2233445566778899001",
  "roleId": "3344556677889900112"
}

DELETE on the same path removes the role and answers with operation: "role_removed".

Both are idempotent, so a role that is already assigned or already absent still returns 200.

Role hierarchy. The bot's highest role must sit above the role it assigns. A bot demoted in the server's role hierarchy loses the ability to assign higher roles even with Manage Roles.

The @everyone role, whose roleId equals the guildId, cannot be assigned or removed.

Create a role with POST /v1/discord/guilds/{guildId}/roles (Create role). name is the only required field.

  • color is decimal (16711680 is red).
  • permissions is a bitfield as a string.
  • hoist and mentionable are booleans.
curl -X POST "https://zernio.com/api/v1/discord/guilds/1098765432109876543/roles?accountId=66b2e19d8c3f5a7e9d0b1c2d" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Beta testers", "color": 3447003, "mentionable": true}'

Response (201):

{
  "data": {
    "id": "3344556677889900112",
    "name": "Beta testers",
    "color": 3447003,
    "position": 3,
    "permissions": "1071698660929",
    "managed": false,
    "mentionable": true,
    "hoist": false
  }
}

PATCH /v1/discord/guilds/{guildId}/roles/{roleId} (Edit role) changes any of those fields, at least one per call, and leaves the rest alone.

DELETE on the same path (Delete role) removes the role from the server and from every member. It answers { "success": true } and cannot be undone.

All three need Manage Roles on the bot and a target role below the bot's highest role.

A server that added the bot before role management shipped must re-invite it, because Discord fixes the permission set at invite time.

Read one member with GET /v1/discord/guilds/{guildId}/members/{userId} (Get member).

Prefix-match usernames and nicknames with GET /v1/discord/guilds/{guildId}/members/search (Search members).

Pinned messages

Pin messages for community operations: the announcement of the week, rules updates, or freshly published posts.

List the current pins, most recent first:

curl "https://zernio.com/api/v1/discord/channels/1234567890123456789/pins?accountId=66b2e19d8c3f5a7e9d0b1c2d" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200), each entry a raw Discord message:

{
  "data": [
    {
      "id": "4455667788990011223",
      "channel_id": "1234567890123456789",
      "content": "Read the rules before posting.",
      "timestamp": "2027-01-01T12:00:00.000Z",
      "attachments": [],
      "embeds": []
    }
  ]
}

Pin a message with PUT on the same path plus its id:

curl -X PUT "https://zernio.com/api/v1/discord/channels/1234567890123456789/pins/4455667788990011223?accountId=66b2e19d8c3f5a7e9d0b1c2d" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200):

{
  "success": true,
  "operation": "message_pinned",
  "channelId": "1234567890123456789",
  "messageId": "4455667788990011223"
}

DELETE on that path unpins and answers with operation: "message_unpinned". Both are idempotent.

A channel holds at most 50 pins. Pinning a 51st returns 400, so unpin one first.

Scheduled events

Scheduled events are separate from messages. They appear in the server's Events panel, and Discord notifies interested members before the start time.

They fit AMAs, tournaments, office hours and livestreams. entity.type picks one of 3 kinds.

An external event (Zoom, in person, a livestream elsewhere) requires both location and endsAt:

curl -X POST https://zernio.com/api/v1/discord/guilds/1098765432109876543/events \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
    "name": "Weekly AMA",
    "description": "Bring your questions about the roadmap.",
    "startsAt": "2027-01-01T18:00:00Z",
    "entity": {
      "type": "external",
      "location": "https://zoom.us/j/123456789",
      "endsAt": "2027-01-01T19:00:00Z"
    }
  }'

Response (200):

{
  "data": {
    "id": "5566778899001122334",
    "guild_id": "1098765432109876543",
    "name": "Weekly AMA",
    "scheduled_start_time": "2027-01-01T18:00:00.000Z",
    "scheduled_end_time": "2027-01-01T19:00:00.000Z",
    "status": 1,
    "entity_type": 3,
    "entity_metadata": { "location": "https://zoom.us/j/123456789" }
  }
}

A voice channel event takes channelId instead, and endsAt is optional.

A stage channel event has the same shape with "type": "stage" and a stage channel id:

{
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "name": "Game night",
  "startsAt": "2027-01-08T20:00:00Z",
  "entity": { "type": "voice", "channelId": "6677889900112233445" }
}

Four more calls read and change an event. Each takes accountId, as a query parameter on the reads and the delete and in the body on the PATCH.

The reads and the PATCH return the same data object as the create call:

CallWhat it does
GET /v1/discord/guilds/{guildId}/eventsEvery event in the server. Add withUserCount=true for the RSVP count in user_count.
GET /v1/discord/guilds/{guildId}/events/{eventId}One event.
PATCH /v1/discord/guilds/{guildId}/events/{eventId}Update any subset of the fields, for example { "name": "Updated title" }.
DELETE /v1/discord/guilds/{guildId}/events/{eventId}Delete it. Answers { "success": true, "deleted": "5566778899001122334" } and keeps no record.

Cancelling. Discord has no cancel endpoint, so cancelling is the PATCH with status: "cancelled". It keeps the event in the server's history as status: 4.

Delete only when no record should remain.

Event propertyValue
NameMax 100 characters
DescriptionMax 1,000 characters
Privacy levelAlways GUILD_ONLY (Discord deprecated public events)
External eventsRequire location (max 100 characters) and endsAt
Voice and stage eventsRequire channelId; endsAt optional
Cover imageOptional base64 data URI (PNG, JPEG, GIF)
Start timeMust be in the future
Was this page helpful?

Inbox

Send 1:1 Discord direct messages from the bot.

Limits & Errors

Analytics availability, what Discord's API does not expose and the common errors when publishing.

On this page

ChannelsRoles and membersPinned messagesScheduled events