Discord Support Tickets
Accept support tickets from Discord slash commands, verify signatures, and store them automatically.
Overview
This workflow connects a Discord bot to your Ubex workspace via an API webhook. When a user runs a slash command like /ticket, Discord sends an interaction payload to your endpoint. The workflow verifies the request signature, extracts the ticket data, writes it to a datasource, and responds back to Discord.
Prerequisites
- A Discord application with a bot and a registered slash command
- Your Discord app's public key for signature verification
- A datasource table (e.g. "Discord Support") with columns:
Title,Message,Tag
Workflow Nodes
1. Flow Start - API Webhook
The entry point receives POST requests from Discord's interaction endpoint.
| Setting | Value |
|---|---|
| Trigger Type | API |
| Method | POST |
| Custom Path | execute |
| Auth | None (Discord verifies via signature) |
Configure your Discord application's Interactions Endpoint URL to point to this workflow's registered endpoint.
2. Code - Signature Verification & Parsing
This Code node does the heavy lifting:
- Reads the
X-Signature-Ed25519andX-Signature-Timestampheaders - Verifies the signature using
verifyMessage()with your Discord app's public key - Parses the request body and routes by interaction type:
- Type 1 (Ping) - returns
{ verified: true, type: "pong" } - Type 2 (Slash command) - extracts
title,message,tag, andauthorfrom command options - Otherwise - returns
{ verified: true, type: "unknown" }
- Type 1 (Ping) - returns
var headers = variables._trigger.headers;
var signature = headers.Get("X-Signature-Ed25519");
var timestamp = headers.Get("X-Signature-Timestamp");
var rawBody = variables._rawBody;
var PUBLIC_KEY = "YOUR_DISCORD_PUBLIC_KEY";
var result = { verified: false, error: "Missing signature or timestamp" };
if (signature && timestamp && rawBody) {
var message = timestamp + rawBody;
var isValid = verifyMessage(message, signature, PUBLIC_KEY);
if (isValid) {
var body = JSON.parse(rawBody);
if (body.type === 1) {
result = { verified: true, type: "pong" };
} else if (body.type === 2) {
var options = body.data.options || [];
result = {
verified: true,
type: "command",
title: options.find(o => o.name === 'title')?.value || '',
message: options.find(o => o.name === 'message')?.value || '',
tag: options.find(o => o.name === 'tag')?.value || null,
author: body.member?.user?.username || 'unknown'
};
}
}
}
result;
Output variable: codeJs1
3. Condition - Route by Type
A 3-way condition routes the flow:
| Branch | Condition | Action |
|---|---|---|
| IF | verified == true AND type != command |
Respond with PONG |
| ELSE IF | type == command |
Write ticket to datasource |
| ELSE | Everything else | Return fallback response |
4a. Simple Output - PONG Response (IF branch)
Responds to Discord's ping verification with the required {"type": 1} payload. This is needed when you first register your interactions endpoint URL.
4b. Write Data - Store Ticket (ELSE IF branch)
Inserts the ticket into the "Discord Support" datasource:
| Column | Value |
|---|---|
| Title | {{codeJs1.title}} |
| Message | {{codeJs1.message}} |
| Tag | {{codeJs1.tag}} |
5. Simple Output - Success Response
After writing the ticket, responds to Discord with:
{
"type": 4,
"data": {
"content": "Report logged successfully"
}
}
This shows a message in the Discord channel confirming the ticket was created.
4c. Simple Output - Fallback (ELSE branch)
Returns {"type": 2} for unrecognized or unverified requests.
Setting Up the Discord Slash Command
Register a slash command in your Discord application with these options:
| Option | Type | Required | Description |
|---|---|---|---|
title |
String | Yes | Short summary of the issue |
message |
String | Yes | Detailed description |
tag |
String | No | Category tag (e.g. bug, feature, question) |
Testing
- Set your Discord app's Interactions Endpoint URL to the workflow's API endpoint
- Discord will send a ping (type 1) - the workflow responds with
{"type": 1}to verify - Run
/ticket title:"Login broken" message:"Can't log in since update" tag:"bug"in your Discord server - Check your "Discord Support" datasource - the ticket should appear
- The bot responds with "✅ Report logged successfully" in the channel
Security Checklist
| Control | Status |
|---|---|
| Ed25519 signature verification | ✅ |
| Timestamp included in signature check | ✅ |
| Public key validation (verifyMessage) | ✅ |
| Interaction type routing (ping vs command) | ✅ |
| Fallback response for unknown types | ✅ |
| POST only endpoint | ✅ |
| Rate limiting (60/min) | ✅ |
| No real secrets in tutorial JSON | ✅ |