Slack Button Workflow - Implementation Guide

Status: Message generator built, webhook integration pending
Date: 2026-02-17


Overview

Interactive Slack messages allow adding contacts to deals with dropdown selections for:

  • Role: CH, IAR, EB, TC, EO, L
  • Association type: internal, seller, buyer
  • Not associated: Skip contact without adding

Message Format

🚫 3160 Crowne Dr, Palmdale, CA | Will (CH) | ? (B)

Stage: Pending | EMD Received
Deal ID: 54223789480
Missing: ❌ TC, EO

For Each Suggested Contact

📧 Jose Maldonado
Email: jose@spgbuyer.com
Source: Gmail (82 messages)
Suggested role: End Buyer (EB)

[Select role ▼] [Association type ▼] [Add to Deal] [Not Associated]
[View in HubSpot] [Mark Complete]

Role Selection

  • Contract Holder (CH)
  • Internal Acq Rep (IAR)
  • End Buyer (EB)
  • Transaction Coordinator (TC)
  • Escrow Officer (EO)
  • Lender (L)

Association Type

  • Internal
  • Seller
  • Buyer

Button Actions

”Add to Deal”

  1. Reads selected role + association type from dropdowns
  2. Calls add-contact-to-deal.js with:
    • Deal ID
    • Contact email
    • Contact name
    • Selected role
  3. Posts confirmation in thread:
    ✅ Added Jose Maldonado as End Buyer (EB)
    Association type: buyer
    
    Re-validating deal...
    Still missing: TC, EO
    

“Not Associated”

  • Marks contact as reviewed but not relevant
  • Removes from suggestion list
  • Posts confirmation:
    ⏭️ Skipped jose@spgbuyer.com
    

“Mark Complete”

  • User confirms all contacts added manually
  • Removes deal from blocking list
  • Posts confirmation:
    ✅ Deal marked complete
    Will re-validate on next compliance run
    

Webhook Integration (Pending)

Required Setup

  1. OpenClaw webhook endpoint:

    POST /api/slack/interactions
    

    Receives button click payloads from Slack

  2. Payload structure:

    {
      "type": "block_actions",
      "actions": [
        {
          "action_id": "add_contact_54223789480_0",
          "type": "button",
          "value": "54223789480|jose@spgbuyer.com|Jose Maldonado"
        }
      ],
      "state": {
        "values": {
          "contact_0": {
            "role_select_54223789480_0": {
              "selected_option": { "value": "EB" }
            },
            "assoc_select_54223789480_0": {
              "selected_option": { "value": "buyer" }
            }
          }
        }
      }
    }
  3. Handler script:

    // Parse action
    const [dealId, email, name] = action.value.split('|');
     
    // Get selected role + association type from state
    const role = state.values.contact_0.role_select.selected_option.value;
    const assocType = state.values.contact_0.assoc_select.selected_option.value;
     
    // Execute add script
    exec(`node add-contact-to-deal.js ${dealId} "${email}" "${name}" ${role}`);
     
    // Post confirmation to thread
    message.send({
      channel: payload.channel.id,
      thread_ts: payload.message.ts,
      text: `✅ Added ${name} as ${role} (${assocType})`
    });

Current Limitations

No Webhook Yet

  • Buttons/dropdowns display correctly
  • Clicking does nothing (no handler configured)
  • Workaround: Use add-contact-to-deal.js manually via command line

Manual Process Until Webhook Built

  1. View Slack message with suggested contacts
  2. Copy contact email + suggested role
  3. Run script:
    node /home/opsadmin/.openclaw/workspace/scripts/add-contact-to-deal.js \
      54223789480 \
      "jose@spgbuyer.com" \
      "Jose Maldonado" \
      EB
  4. Re-validate:
    node /home/opsadmin/.openclaw/workspace/scripts/validate-deal-v3.js 54223789480

Implementation Steps (When Ready)

Step 1: Configure Slack App

  1. Go to https://api.slack.com/apps
  2. Select Better Acquisitions app
  3. Enable “Interactivity & Shortcuts”
  4. Set Request URL to OpenClaw webhook endpoint
  5. Add scopes: chat:write, chat:write.public

Step 2: Build Webhook Handler

Create /home/opsadmin/.openclaw/workspace/scripts/slack-interaction-handler.js:

// Parse Slack interaction payload
// Extract deal ID, contact email/name, role, association type
// Call add-contact-to-deal.js
// Post confirmation to thread

Step 3: Test End-to-End

  1. Post test message with buttons
  2. Click “Add to Deal”
  3. Verify:
    • Contact created/found in HubSpot
    • Associated with deal
    • Role note added
    • Confirmation posted to thread
    • Re-validation shows updated status

Step 4: Deploy to Daily Cron

Update 6 AM cron to use button messages instead of plain text suggestions.


Message Generator Usage

Script: /workspace/scripts/generate-slack-contact-suggestion.js

Example:

const { generateContactSuggestionBlocks } = require('./generate-slack-contact-suggestion.js');
 
const deal = {
  id: '54223789480',
  name: '3160 Crowne Dr, Palmdale, CA',
  stage: 'Pending | EMD Received',
  missing: [{ role: 'TC' }, { role: 'EO' }]
};
 
const contacts = [
  {
    name: 'Jose Maldonado',
    email: 'jose@spgbuyer.com',
    source: 'Gmail',
    suggestedRole: 'EB'
  }
];
 
const blocks = generateContactSuggestionBlocks(deal, contacts);
 
// Send to Slack
message.send({
  channel: 'C0AFCU58QSW',
  blocks: blocks
});

Future Enhancements

Batch Operations

  • “Add All Suggested” button (uses suggested roles)
  • “Skip All” button
  • Bulk validation after multiple adds

Smart Suggestions

  • Learn from past associations (if User X added Contact Y as EB, suggest EB next time)
  • Prioritize contacts by communication frequency
  • Flag suspicious suggestions (email domain mismatch, etc.)

Validation Feedback

  • Show before/after comparison when contact added
  • Highlight which missing roles were satisfied
  • Show remaining blockers inline

Last updated: 2026-02-17 04:15 AM PST