IntermediateDiscord

Discord Support Tickets

Let users submit support tickets via Discord slash commands, verified and stored automatically.

Click to expand
Flow StartAPI webhookCodecodeJs1ConditionIFELSE IFELSESimple Output{"type": 1}Write DataDiscord SupportSimple Output✅ Report loggedSimple Output{"type": 2}

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:

  1. Reads the X-Signature-Ed25519 and X-Signature-Timestamp headers
  2. Verifies the signature using verifyMessage() with your Discord app's public key
  3. 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, and author from command options
    • Otherwise - returns { verified: true, type: "unknown" }
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

  1. Set your Discord app's Interactions Endpoint URL to the workflow's API endpoint
  2. Discord will send a ping (type 1) - the workflow responds with {"type": 1} to verify
  3. Run /ticket title:"Login broken" message:"Can't log in since update" tag:"bug" in your Discord server
  4. Check your "Discord Support" datasource - the ticket should appear
  5. 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