Request discount approval in Slack for HubSpot deals using code
high complexityCost: $0
Prerequisites
Prerequisites
- Node.js or Python
- HubSpot private app token (read + write scopes for deals)
- Slack Bot Token with
chat:writescope + interactive messages enabled - A server to handle Slack interactivity callbacks
Architecture
This requires two endpoints:
- Webhook receiver — receives HubSpot deal change events, checks discount threshold, sends Slack message with Approve/Deny buttons
- Interactivity handler — receives Slack button clicks, updates HubSpot deal, notifies the rep
Step 1: Send approval request with buttons
When a deal's discount exceeds the threshold, post a message with Block Kit interactive buttons:
# In your webhook handler after checking discount > 15%
slack.chat_postMessage(
channel=os.environ["DEAL_DESK_CHANNEL"],
text=f"Discount approval needed for {deal_name}",
blocks=[
{"type": "section", "text": {"type": "mrkdwn",
"text": f"🏷️ *Discount Approval Needed*\n*Deal:* {deal_name}\n*Amount:* ${amount:,.0f}\n*Discount:* {discount}%"}},
{"type": "actions", "elements": [
{"type": "button", "text": {"type": "plain_text", "text": "✅ Approve"},
"style": "primary", "action_id": "approve_discount",
"value": json.dumps({"deal_id": deal_id, "discount": discount})},
{"type": "button", "text": {"type": "plain_text", "text": "❌ Deny"},
"style": "danger", "action_id": "deny_discount",
"value": json.dumps({"deal_id": deal_id})}
]}
]
)Step 2: Handle the button click
Set up a Slack interactivity endpoint (configure in your Slack app under Interactivity & Shortcuts):
@app.route("/slack/interact", methods=["POST"])
def handle_interaction():
payload = json.loads(request.form["payload"])
action = payload["actions"][0]
data = json.loads(action["value"])
user = payload["user"]["name"]
approved = action["action_id"] == "approve_discount"
status = "Approved" if approved else "Denied"
# Update HubSpot
requests.patch(
f"https://api.hubapi.com/crm/v3/objects/deals/{data['deal_id']}",
headers={**HEADERS, "Content-Type": "application/json"},
json={"properties": {"discount_approval": status}}
)
# Update the Slack message to show the decision
slack.chat_update(
channel=payload["channel"]["id"],
ts=payload["message"]["ts"],
text=f"Discount {'approved' if approved else 'denied'} by {user}",
blocks=[
{"type": "section", "text": {"type": "mrkdwn",
"text": f"{'✅' if approved else '❌'} Discount *{status}* by {user}"}}
]
)
return "", 200Slack interactivity setup
You must configure your Slack app's Request URL under Interactivity & Shortcuts to point to your server's /slack/interact endpoint. Without this, button clicks do nothing.
Cost
- Free — hosting costs only. No per-execution fees.
Need help implementing this?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.