Welcome to The Crimson Market Developers Portal

Build powerful integrations with The Crimson Market API. Create OAuth applications, manage your credentials, and access our comprehensive documentation to bring trading functionality to your platform.

Developers Documentation

TCM OAuth Integration Docs

SDK-backed guidance for @crimsoncorp/oauth-react, plus portal-specific setup details for apps, scopes, and redirect registration.

Discord Bot API

Create a service.discord client and read safe bot, giveaway, guild, and leaderboard data for community sites and widgets.

Local portal docs

The TCM Discord Bot API lets approved server-side apps read safe Discord bot data and manage Discord bot settings for servers the app owner is allowed to manage.

Read endpoints can power community sites, widgets, dashboards, and giveaway growth pages. Management endpoints use the same server-owner permission checks as Discord Manager, so a developer app can only change a guild when the app owner has a linked Discord account and can manage that Discord server.

Create A Service Client

Create a machine-to-machine service client in the Developers portal.

Use:

  • Audience: service.discord
  • Scopes:
  • discordbot:read
  • discordbot:leaderboards:read
  • discordbot:manage
  • discordbot:giveaways:write
  • discordbot:leveling:write
  • discordbot:economy:write

The client secret is shown once. Store it only on your backend.

Mint A Token

Use the OAuth token endpoint with client_credentials.

curl -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials \
  -d resource=service.discord \
  -d scope="discordbot:read discordbot:leaderboards:read" \
  https://www.thecrimsonmarket.com/mana/oauth/token

The response contains a short-lived bearer token:

{
  "access_token": "<jwt>",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "discordbot:read discordbot:leaderboards:read",
  "aud": "service.discord"
}

Every API request must send:

Authorization: Bearer <access_token>

Base URL

Production:

https://www.thecrimsonmarket.com/mana/discord/api/v1

Development:

https://dev.portal.raum.au/mana/discord/api/v1

Endpoints

Bot Status

Requires discordbot:read.

GET /status

Returns bot runtime health and the enabled public API capabilities.

Public Giveaways

Requires discordbot:read.

GET /giveaways?limit=25
GET /guilds/{guildId}/giveaways?limit=25

Returns active public giveaways, Discord join/message URLs, entry methods, entry counts, end timestamps, and server display metadata.

Guild Summary

Requires discordbot:read.

GET /guilds/{guildId}

Returns safe server metadata for a server where the bot is installed:

  • server id
  • server name
  • icon URL
  • member count when Discord provides it
  • Discord guild features
  • bot join date
  • availability status

This endpoint does not return channel lists, role lists, private dashboard config, moderation cases, member lists, or server-owner data.

Server XP Leaderboard

Requires discordbot:leaderboards:read.

GET /guilds/{guildId}/levels/leaderboard?limit=10

Returns public server leveling rows:

  • rank
  • Discord user id
  • display name
  • username
  • XP
  • level
  • message count
  • voice seconds

Server Credit Leaderboard

Requires discordbot:leaderboards:read.

GET /guilds/{guildId}/economy/leaderboard?period=season&limit=10

Supported periods:

  • season
  • weekly
  • monthly
  • allTime

Returns public server credit leaderboard rows. It does not expose spendable balances or allow purchases.

Manageable Guilds

Requires discordbot:manage.

GET /me/guilds

Returns the bot servers the developer app owner can manage. The owner must have Discord linked to their TCM account.

Guild Management Overview

Requires discordbot:manage.

GET /guilds/{guildId}/management

Returns dashboard-equivalent setup data for one server the app owner can manage, including eligible channels, roles, giveaway setup data, command status, and feature configuration.

Create Giveaway

Requires discordbot:giveaways:write.

POST /guilds/{guildId}/giveaways

Creates a giveaway using the same payload fields and validation as Discord Manager.

Update Leveling Config

Requires discordbot:leveling:write.

PATCH /guilds/{guildId}/leveling/config

Updates server leveling settings, including message XP, voice XP, level roles, rank-card behavior, global level-up webhooks, and per-level-role reward webhooks.

Each levelRoleRewards row can include its own outbound webhook. The webhook is sent only after that specific Discord role is awarded to the member.

{
  "levelRoleRewards": [
    {
      "level": 10,
      "roleId": "123456789012345678",
      "webhookEnabled": true,
      "webhookUrl": "https://example.com/api/discord/level-role-reward",
      "webhookHeaderName": "X-TCM-Webhook-Key",
      "webhookApiKey": "replace-with-shared-key",
      "webhookSigningSecret": "optional-hmac-secret"
    }
  ]
}

Leave webhookApiKey or webhookSigningSecret blank when updating a row to keep the saved secret.

Update Economy Config

Requires discordbot:economy:write.

PATCH /guilds/{guildId}/economy/config

Updates server credit economy settings, including reward shop behavior and purchase webhooks.

Command Status And Refresh

Requires discordbot:manage.

GET /guilds/{guildId}/commands
POST /guilds/{guildId}/commands/refresh

Checks slash-command registration status or refreshes commands for one server the app owner can manage.

Error Responses

Common responses:

  • 401 Missing bearer token
  • 401 Invalid token
  • 401 Invalid token audience
  • 401 Service token required
  • 403 Insufficient scope
  • 403 Developer API client is not active
  • 403 The developer app owner must link Discord before using Discord management APIs
  • 403 You do not have permission to manage that Discord server
  • 404 The bot is not in that Discord server or the server is unavailable

Example

const tokenResponse = await fetch("https://www.thecrimsonmarket.com/mana/oauth/token", {
  method: "POST",
  headers: {
    Authorization: `Basic ${Buffer.from(`${process.env.TCM_CLIENT_ID}:${process.env.TCM_CLIENT_SECRET}`).toString("base64")}`,
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams({
    grant_type: "client_credentials",
    resource: "service.discord",
    scope: "discordbot:read discordbot:leaderboards:read",
  }),
});

const { access_token } = await tokenResponse.json();

const leaderboard = await fetch(
  "https://www.thecrimsonmarket.com/mana/discord/api/v1/guilds/1117111237231267884/levels/leaderboard",
  {
    headers: {
      Authorization: `Bearer ${access_token}`,
    },
  },
).then((response) => response.json());

Permission Boundaries

Management requests are authorized in this order:

  • The bearer token must be valid for the service.discord audience.
  • The token must contain the required Discord bot API scope.
  • The token client ID must resolve to an active Portal developer app.
  • The developer app owner must have a linked Discord ID.
  • For every guild action, the bot checks that Discord user is still a member and has Administrator, Manage Server, or Manage Channels.

The API is designed for safe external consumption:

  • Read public bot and server data.
  • Read active public giveaways.
  • Read public leaderboards.
  • Manage settings only for servers the app owner can manage.
  • Do not expose moderation history.
  • Do not expose role/member/channel inventories.
  • Do not allow arbitrary Discord messages or moderation actions.

Outbound Webhook Events

Server owners can configure webhook delivery from the Discord Manager dashboard or through management API settings.

  • discord.level_up: sent when a member reaches a new server level. Includes guild ID, Discord ID, username/display name, previous/current level, XP totals, source, role rewards, and credit rewards.
  • discord.level_role_reward: sent when a configured level role reward is actually awarded. Includes guild ID, Discord ID, username/display name, previous/current level, reward level, XP totals, source, and the awarded role ID/name.
  • discord.reward_purchase: sent when a member buys a reward shop item. Includes guild ID, Discord ID, item details, purchase ID, status, price, role reward details, and remaining balance.

Webhook requests support a configurable API key header and optional x-tcm-signature HMAC SHA-256 signature over {timestamp}.{jsonBody}.