Guide

Bot command sync

Your bot already knows its own command list. Velora does not — so a viewer landing on the bot's profile page sees nothing. One POST pushes the whole list across, and it stays there until you push a different one. It is a full replacement: send everything every time, and there is nothing else to track.

Synced commands appear on the bot profile with a badge showing your application name. You need an active bot connection before the first sync will succeed — that is what the bot:connect scope is for.

  • Showing viewers what commands are available in chat
  • Keeping the bot profile page up to date with your app’s current command set
  • Automatically managing conflicts with Velora Bot Studio (VBS) commands

The call

POST/api/integrations/oauth/bot/commands/syncbot:commands

Push the complete list of commands from your application. Every call replaces all previously synced commands from your app.

curl — request
curl -X POST https://api.velora.tv/api/integrations/oauth/bot/commands/sync \
  -H "Authorization: Bearer YOUR_OAUTH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "botId": "bot-uuid-here",
    "commands": [
      {
        "trigger": "lurk",
        "description": "Let the streamer know you are lurking",
        "permissions": { "level": "everyone" },
        "cooldown": { "globalCooldown": 5, "userCooldown": 30 }
      },
      {
        "trigger": "so",
        "description": "Shoutout another streamer",
        "permissions": { "level": "moderators" },
        "cooldown": { "globalCooldown": 0, "userCooldown": 0 }
      },
      {
        "trigger": "uptime",
        "description": "Shows how long the stream has been live"
      },
      {
        "trigger": "secret",
        "description": "Hidden admin command",
        "isPublic": false
      }
    ]
  }'
Response 200
{
  "success": true,
  "synced": {
    "total": 4,
    "removed": 0
  },
  "overrides": {
    "vbsCommandsDisabled": 1,
    "vbsCommandsRestored": 0
  }
}

Request body

FieldTypeDescription
botIdstringThe bot ID to sync commands for. Must have an active connection.
commandsarrayArray of command objects. Max 500.

Command object

FieldTypeRequiredDescription
triggerstringYesCommand trigger, max 50 characters. A leading ! is stripped automatically.
descriptionstringNoWhat the command does. Max 500 characters.
permissionsobjectNoWho can use this command. See permission levels below.
cooldownobjectNo{ globalCooldown: seconds, userCooldown: seconds }
aliasesstring[]NoAlternative triggers. Max 20.
isPublicbooleanNoShow on the profile page. Default true.

Full replacement semantics

Your application must push the complete list of commands on every save or change. This endpoint replaces all previously synced commands from your app.

  • If you send 10 commands, then later send 8 — the 2 removed commands are deleted from the profile.
  • If you send an empty commands array, all previously synced commands are removed.
  • This simplifies your implementation: no need to track adds, updates or deletes individually.

Permission levels

The permissions.level field controls who can see and use the command.

LevelDescription
everyoneAll viewers can use this command
followersOnly followers, optionally with a minimum follow age
subscribersAny subscriber tier
tier1Tier 1+ subscribers
tier2Tier 2+ subscribers
tier3Tier 3 subscribers only
vipsVIPs and above
moderatorsModerators and streamer only
streamer_onlyOnly the streamer can use this command

When a trigger collides with Velora Bot Studio

When you sync a command whose trigger matches an existing Velora Bot Studio (VBS) command, Velora resolves it for you.

Auto-disable

The matching VBS command is automatically disabled to prevent duplicate responses. Your synced command takes priority.

Auto-restore

When you remove a command from your sync list, or disconnect, the VBS command is automatically re-enabled.

No permanent changes

The VBS command is never deleted — only temporarily disabled. The streamer’s VBS configuration is always preserved.

What happens on disconnect

When your app disconnects from a bot, or the user revokes access:

  • All synced commands from your app are removed from the profile.
  • Any VBS commands that were overridden by your app are restored.
  • The bot profile immediately reflects these changes.

Scopes and rate limits

ScopePurposeRate limit
bot:commandsSync command lists to bot profiles10 requests / 60 seconds
bot:connectRequired to establish the bot connection first—

Since this is a full-replacement endpoint, you typically only need to call it when commands change — not on every bot startup.

Error handling

StatusMeaning
400Invalid request body, duplicate triggers, or a validation error
401Invalid or expired OAuth token
403Missing bot:commands scope
404Bot not found, not owned by the user, or no active connection
429Rate limit exceeded — 10 requests per 60 seconds

A complete implementation

A complete TypeScript example for syncing commands from a Streamer.bot-style application, including the sync call and reading the override counts back.

TypeScript
// Velora Bot Command Sync Example

const VELORA_API = 'https://api.velora.tv/api/integrations/oauth';

interface VeloraCommand {
  trigger: string;
  description?: string;
  permissions?: { level: string };
  cooldown?: { globalCooldown: number; userCooldown: number };
  aliases?: string[];
  isPublic?: boolean;
}

async function syncCommands(
  accessToken: string,
  botId: string,
  commands: VeloraCommand[]
) {
  const response = await fetch(`${VELORA_API}/bot/commands/sync`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ botId, commands }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || 'Failed to sync commands');
  }

  return response.json();
}

// Example: Sync after user saves command changes
async function onCommandsSaved(botId: string, token: string) {
  const commands: VeloraCommand[] = [
    {
      trigger: 'lurk',
      description: 'Let the streamer know you are lurking',
      permissions: { level: 'everyone' },
      cooldown: { globalCooldown: 5, userCooldown: 30 },
    },
    {
      trigger: 'so',
      description: 'Shoutout another streamer',
      permissions: { level: 'moderators' },
      cooldown: { globalCooldown: 0, userCooldown: 0 },
    },
    {
      trigger: 'uptime',
      description: 'Shows how long the stream has been live',
    },
    {
      trigger: 'rank',
      description: 'Check your chat rank',
      permissions: { level: 'followers' },
    },
  ];

  const result = await syncCommands(token, botId, commands);
  console.log(`Synced ${result.synced.total} commands`);

  if (result.overrides.vbsCommandsDisabled > 0) {
    console.log(
      `${result.overrides.vbsCommandsDisabled} VBS command(s) auto-disabled`
    );
  }
}

Next