Skip to content

Slack Integration ​

Receive webhooks from Slack for events, slash commands, and interactive components.

Setup ​

1. Create a Source in WebhookRelay ​

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/sources \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Slack App",
    "slug": "slack",
    "verificationConfig": {
      "type": "slack",
      "secret": "your-signing-secret"
    }
  }'

Save your webhook URL:

https://api.hookbase.app/ingest/{orgSlug}/slack

2. Create a Slack App ​

  1. Go to Slack API
  2. Click Create New App
  3. Choose From scratch
  4. Name your app and select a workspace
  5. Click Create App

3. Configure Event Subscriptions ​

  1. In your Slack app settings, go to Event Subscriptions
  2. Toggle Enable Events to On
  3. Enter your WebhookRelay URL as the Request URL
  4. Slack will send a verification challenge (WebhookRelay handles this)
  5. Under Subscribe to bot events, add events like:
    • message.channels
    • message.im
    • app_mention
    • reaction_added
  6. Click Save Changes

4. Get Your Signing Secret ​

  1. Go to Basic Information in your Slack app
  2. Under App Credentials, find Signing Secret
  3. Copy this secret to your WebhookRelay source configuration

5. Install the App ​

  1. Go to Install App in your Slack app settings
  2. Click Install to Workspace
  3. Authorize the requested permissions

Signature Verification ​

Slack signs requests using HMAC-SHA256. The signature is sent in headers:

X-Slack-Request-Timestamp: 1531420618
X-Slack-Signature: v0=a2114d57b48eac39b9ad189dd8316235a7b4a8d21a10bd27519666489c69b503

WebhookRelay verifies this automatically:

json
{
  "verificationConfig": {
    "type": "slack",
    "secret": "your-signing-secret"
  }
}

Timestamp Tolerance ​

Slack signatures include a timestamp. WebhookRelay rejects requests older than 5 minutes to prevent replay attacks.

Event Types ​

Message Events ​

json
{
  "token": "...",
  "team_id": "T1234567",
  "event": {
    "type": "message",
    "channel": "C1234567",
    "user": "U1234567",
    "text": "Hello world",
    "ts": "1234567890.123456"
  },
  "type": "event_callback",
  "event_id": "Ev1234567",
  "event_time": 1234567890
}

App Mention ​

json
{
  "token": "...",
  "team_id": "T1234567",
  "event": {
    "type": "app_mention",
    "user": "U1234567",
    "text": "<@U0LAN0Z89> help",
    "channel": "C1234567",
    "ts": "1234567890.123456"
  },
  "type": "event_callback"
}

Reaction Added ​

json
{
  "token": "...",
  "team_id": "T1234567",
  "event": {
    "type": "reaction_added",
    "user": "U1234567",
    "reaction": "thumbsup",
    "item": {
      "type": "message",
      "channel": "C1234567",
      "ts": "1234567890.123456"
    }
  },
  "type": "event_callback"
}

Slash Commands ​

Setup ​

  1. Go to Slash Commands in your Slack app
  2. Click Create New Command
  3. Enter your command (e.g., /mycommand)
  4. Set Request URL to your WebhookRelay URL
  5. Click Save

Payload Format ​

json
{
  "command": "/mycommand",
  "text": "argument text",
  "user_id": "U1234567",
  "user_name": "username",
  "channel_id": "C1234567",
  "channel_name": "general",
  "team_id": "T1234567",
  "response_url": "https://hooks.slack.com/commands/..."
}

Responding to Commands ​

Your destination should respond within 3 seconds with:

json
{
  "response_type": "in_channel",
  "text": "Command received!"
}

Or use the response_url for delayed responses.

Interactive Components ​

Setup ​

  1. Go to Interactivity & Shortcuts
  2. Toggle Interactivity to On
  3. Set Request URL to your WebhookRelay URL
  4. Click Save Changes

Button Click Payload ​

json
{
  "type": "block_actions",
  "user": {
    "id": "U1234567",
    "username": "user"
  },
  "actions": [{
    "action_id": "button_click",
    "block_id": "block_1",
    "type": "button",
    "value": "click_me_123"
  }],
  "response_url": "https://hooks.slack.com/actions/...",
  "trigger_id": "1234567890.123456"
}

Transform Examples ​

Log to Database ​

javascript
function transform(payload) {
  if (payload.type !== 'event_callback') {
    return payload;
  }

  const event = payload.event;

  return {
    event_type: event.type,
    team_id: payload.team_id,
    channel_id: event.channel,
    user_id: event.user,
    text: event.text,
    timestamp: event.ts,
    raw_event: payload
  };
}

Forward to Discord ​

javascript
function transform(payload) {
  if (payload.type !== 'event_callback' || payload.event.type !== 'message') {
    return null; // Skip non-message events
  }

  const event = payload.event;

  return {
    content: event.text,
    username: `Slack (${event.user})`,
    embeds: [{
      color: 0x4A154B,
      footer: {
        text: `From Slack #${event.channel}`
      },
      timestamp: new Date(parseFloat(event.ts) * 1000).toISOString()
    }]
  };
}

Extract Mentions ​

javascript
function transform(payload) {
  if (payload.event?.type !== 'app_mention') {
    return payload;
  }

  const event = payload.event;
  const text = event.text.replace(/<@[A-Z0-9]+>\s*/g, '').trim();

  return {
    action: 'mention',
    user: event.user,
    channel: event.channel,
    command: text,
    timestamp: event.ts
  };
}

Filter Examples ​

Only Message Events ​

json
{
  "name": "Messages Only",
  "logic": "and",
  "conditions": [
    {
      "field": "event.type",
      "operator": "equals",
      "value": "message"
    }
  ]
}

Exclude Bot Messages ​

json
{
  "name": "Non-Bot Messages",
  "logic": "and",
  "conditions": [
    {
      "field": "event.bot_id",
      "operator": "not_exists",
      "value": ""
    }
  ]
}

Specific Channel ​

json
{
  "name": "Alerts Channel",
  "logic": "and",
  "conditions": [
    {
      "field": "event.channel",
      "operator": "equals",
      "value": "C1234567"
    }
  ]
}

App Mentions Only ​

json
{
  "name": "App Mentions",
  "logic": "and",
  "conditions": [
    {
      "field": "event.type",
      "operator": "equals",
      "value": "app_mention"
    }
  ]
}

URL Verification ​

When you first set up Event Subscriptions, Slack sends a verification challenge:

json
{
  "type": "url_verification",
  "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
  "token": "..."
}

WebhookRelay automatically responds with the challenge, so you don't need to handle this.

Best Practices ​

  1. Respond quickly: Slack expects responses within 3 seconds for slash commands and interactions

  2. Use response_url: For longer operations, acknowledge immediately and use response_url for the actual response

  3. Handle retries: Slack may retry failed requests; check for X-Slack-Retry-Num header

  4. Filter bot messages: Exclude bot messages to prevent loops

  5. Verify the signature: Always use signature verification in production

Troubleshooting ​

URL Verification Failed ​

  1. Ensure your source is configured with the correct signing secret
  2. Check that the WebhookRelay endpoint is accessible from the internet
  3. Verify the URL doesn't have extra characters or spaces

Events Not Arriving ​

  1. Check Event Subscriptions is enabled
  2. Verify the correct events are subscribed
  3. Ensure the app is installed to the workspace
  4. Check the app has required OAuth scopes

Signature Verification Failed ​

  1. Use the Signing Secret, not the Verification Token
  2. Verify the secret is copied correctly (no extra spaces)
  3. Check if the request timestamp is too old (>5 minutes)

Released under the MIT License.