Skip to main content
Like AOF? Give us a star!
If you find AOF useful, please star us on GitHub. It helps us reach more developers and grow the community.

Discord Integration Reference

Complete reference for Discord Interactions API integration in AOF.

Configuration​

Trigger Specification​

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: discord-ops
labels:
platform: discord
spec:
type: Discord
config:
# Bot credentials (required)
bot_token: ${DISCORD_BOT_TOKEN}
application_id: ${DISCORD_APPLICATION_ID}
public_key: ${DISCORD_PUBLIC_KEY}

# Guild restrictions (optional)
guild_ids:
- "123456789012345678"

# Role restrictions (optional)
allowed_roles:
- "987654321098765432" # Admin role
- "876543210987654321" # DevOps role

# Command definitions
commands:
/status:
agent: devops
description: "Check system status"

/deploy:
agent: deployer
description: "Deploy application"

/diagnose:
fleet: rca-fleet
description: "Root cause analysis"

# Default for unmatched commands
default_agent: devops

Environment Variables​

VariableRequiredDescription
DISCORD_BOT_TOKENYesBot token from Developer Portal
DISCORD_APPLICATION_IDYesApplication ID
DISCORD_PUBLIC_KEYYesEd25519 public key for verification

Daemon Configuration​

# daemon.yaml
platforms:
discord:
enabled: true
webhook_path: /webhook/discord

# Bot credentials
bot_token: ${DISCORD_BOT_TOKEN}
application_id: ${DISCORD_APPLICATION_ID}
public_key: ${DISCORD_PUBLIC_KEY}

# Optional restrictions
guild_ids:
- ${DISCORD_GUILD_ID}

Interaction Types​

Slash Commands (Type 2)​

{
"id": "interaction-id",
"type": 2,
"application_id": "app-id",
"token": "interaction-token",
"data": {
"id": "command-id",
"name": "agent",
"options": [
{ "name": "action", "value": "run" },
{ "name": "agent_id", "value": "k8s-ops" }
]
},
"guild_id": "guild-id",
"channel_id": "channel-id",
"member": {
"user": {
"id": "user-id",
"username": "developer",
"discriminator": "0001"
},
"roles": ["role-id-1", "role-id-2"]
}
}

Message Components (Type 3)​

{
"id": "interaction-id",
"type": 3,
"token": "interaction-token",
"data": {
"custom_id": "approve_deployment",
"component_type": 2
},
"message": {
"id": "original-message-id",
"content": "..."
},
"member": {
"user": { "id": "user-id", "username": "admin" }
}
}
{
"id": "interaction-id",
"type": 5,
"token": "interaction-token",
"data": {
"custom_id": "feedback_modal",
"components": [
{
"type": 1,
"components": [
{
"type": 4,
"custom_id": "feedback_text",
"value": "User's input text"
}
]
}
]
}
}

Slash Commands​

Command Structure​

{
"name": "agent",
"description": "Manage AOF agents",
"options": [
{
"type": 3,
"name": "action",
"description": "Action to perform",
"required": true,
"choices": [
{ "name": "run", "value": "run" },
{ "name": "status", "value": "status" },
{ "name": "stop", "value": "stop" }
]
},
{
"type": 3,
"name": "agent_id",
"description": "Agent ID",
"required": true
}
]
}

Option Types​

TypeNameDescription
1SUB_COMMANDSubcommand
2SUB_COMMAND_GROUPSubcommand group
3STRINGString input
4INTEGERInteger input
5BOOLEANBoolean input
6USERUser mention
7CHANNELChannel selection
8ROLERole selection
10NUMBERDecimal number
11ATTACHMENTFile attachment

Built-in Commands​

AOF registers these commands automatically:

CommandOptionsDescription
/agentaction, agent_idManage agents
/taskaction, descriptionManage tasks
/fleetactionManage fleets
/flowworkflowExecute workflows

Registering Commands​

# Register commands globally
aofctl discord register-commands

# Register to specific guild (faster updates)
aofctl discord register-commands --guild-id 123456789012345678

Response Formatting​

Basic Embed​

{
"type": 4,
"data": {
"embeds": [
{
"title": "📊 System Status",
"description": "All systems operational",
"color": 5763719,
"fields": [
{ "name": "Nodes", "value": "✅ 3/3 Ready", "inline": true },
{ "name": "Pods", "value": "✅ 45/45 Running", "inline": true },
{ "name": "Services", "value": "✅ 12/12 Active", "inline": true }
],
"footer": { "text": "Last updated" },
"timestamp": "2024-01-15T10:30:00.000Z"
}
]
}
}

With Components​

{
"type": 4,
"data": {
"embeds": [{ "title": "Status", "description": "..." }],
"components": [
{
"type": 1,
"components": [
{
"type": 2,
"style": 1,
"label": "Refresh",
"custom_id": "refresh_status"
},
{
"type": 2,
"style": 3,
"label": "View Logs",
"custom_id": "view_logs"
},
{
"type": 2,
"style": 4,
"label": "Restart",
"custom_id": "restart_service"
}
]
}
]
}
}

Component Types​

TypeNameDescription
1Action RowContainer for components
2ButtonClickable button
3String SelectDropdown menu
4Text InputText input (modals only)
5User SelectUser selection menu
6Role SelectRole selection menu
7Mentionable SelectUser/role selection
8Channel SelectChannel selection

Button Styles​

StyleNameColorUse Case
1PrimaryBlueMain actions
2SecondaryGraySecondary actions
3SuccessGreenConfirmations
4DangerRedDestructive actions
5LinkGrayExternal links
{
"type": 9,
"data": {
"custom_id": "feedback_modal",
"title": "Provide Feedback",
"components": [
{
"type": 1,
"components": [
{
"type": 4,
"custom_id": "feedback_text",
"label": "Your Feedback",
"style": 2,
"placeholder": "Enter feedback...",
"required": true,
"max_length": 1000
}
]
}
]
}
}

Signature Verification​

Ed25519 Verification​

Discord uses Ed25519 for signature verification:

// Headers required
X-Signature-Ed25519: <hex_signature>
X-Signature-Timestamp: <timestamp>

// Message to verify
message = timestamp + request_body

// Verification
ed25519::verify(public_key, message, signature)

Verification Implementation​

use ed25519_dalek::{Signature, Verifier, VerifyingKey};

fn verify_signature(
public_key: &VerifyingKey,
timestamp: &str,
body: &[u8],
signature: &[u8; 64]
) -> bool {
let message = format!("{}{}", timestamp, String::from_utf8_lossy(body));
let sig = Signature::from_bytes(signature);
public_key.verify(message.as_bytes(), &sig).is_ok()
}

API Endpoints​

Respond to Interaction​

POST https://discord.com/api/v10/interactions/{interaction_id}/{interaction_token}/callback

{
"type": 4,
"data": {
"content": "Response text",
"embeds": [...],
"components": [...]
}
}

Response Types​

TypeNameDescription
1PONGACK ping
4CHANNEL_MESSAGEReply with message
5DEFERRED_CHANNEL_MESSAGEACK, send later
6DEFERRED_UPDATE_MESSAGEACK component, update later
7UPDATE_MESSAGEUpdate original message
9MODALShow modal dialog

Edit Original Response​

PATCH https://discord.com/api/v10/webhooks/{application_id}/{interaction_token}/messages/@original

{
"content": "Updated content",
"embeds": [...]
}

Send Follow-up Message​

POST https://discord.com/api/v10/webhooks/{application_id}/{interaction_token}

{
"content": "Follow-up message"
}

Register Global Commands​

PUT https://discord.com/api/v10/applications/{application_id}/commands

[
{ "name": "agent", "description": "...", "options": [...] },
{ "name": "task", "description": "...", "options": [...] }
]

Register Guild Commands​

PUT https://discord.com/api/v10/applications/{application_id}/guilds/{guild_id}/commands

[...]

Rate Limits​

EndpointLimitWindow
Interaction response3 secondsMust respond
Deferred response15 minutesFollow-up window
Global commands200/dayPer application
Guild commands200/dayPer guild
Message send5/5sPer channel

Error Handling​

Common Errors​

CodeDescriptionSolution
10003Unknown channelVerify channel ID
10008Unknown messageMessage deleted
10062Unknown interactionTimeout expired
40001UnauthorizedCheck bot token
40060Interaction acknowledgedAlready responded
50001Missing accessCheck permissions
50035Invalid form bodyCheck request format

Error Response Format​

{
"code": 50035,
"message": "Invalid Form Body",
"errors": {
"data": {
"embeds": {
"0": {
"title": {
"_errors": [
{ "code": "BASE_TYPE_MAX_LENGTH", "message": "..." }
]
}
}
}
}
}
}

Limits​

ResourceLimit
Embed title256 characters
Embed description4096 characters
Embed fields25 fields
Field name256 characters
Field value1024 characters
Total embed6000 characters
Components per row5
Action rows5
Select options25
Button label80 characters

Security Best Practices​

  1. Always verify signatures - Never skip Ed25519 verification
  2. Validate user roles - Check allowed_roles before execution
  3. Use ephemeral messages - For sensitive information
  4. Rate limit commands - Prevent abuse
  5. Audit logging - Log all command invocations
  6. Secure tokens - Never expose in logs or responses

Testing​

Discord Developer Portal​

Test in the Developer Portal:

  1. Go to your application
  2. Navigate to "Bot" section
  3. Use "Interactions Endpoint URL" testing

Local Development​

# Use ngrok for local testing
ngrok http 8080

# Update Interactions Endpoint URL
# https://xxx.ngrok.io/webhook/discord

Interaction Verification Test​

# Test PING verification
curl -X POST http://localhost:8080/webhook/discord \
-H "Content-Type: application/json" \
-H "X-Signature-Ed25519: <signature>" \
-H "X-Signature-Timestamp: <timestamp>" \
-d '{"type": 1}'

Troubleshooting​

Bot Not Responding​

  1. Check webhook URL is correct
  2. Verify signature verification passes
  3. Confirm bot has required permissions
  4. Check AOF daemon logs

Commands Not Appearing​

  1. Wait 1 hour for global commands
  2. Use guild commands for instant updates
  3. Check command registration succeeded
  4. Verify bot is in the guild

Signature Verification Failing​

  1. Verify public key is correct
  2. Check timestamp header is present
  3. Ensure body hasn't been modified
  4. Verify hex decoding is correct

See Also​