Skip to content

Slack Integration

Connect TruthVouch to Slack to receive real-time alerts, manage AI governance policies, and verify content directly from Slack. Use slash commands to query verification results and interactive buttons for quick actions.

Setup

1. Create Slack App

Visit api.slack.com/apps and create a new app:

  • App Name: “TruthVouch”
  • Development Workspace: Your workspace

2. Enable Features

In your app settings:

  • Permissions: Add OAuth scopes
    • chat:write (send messages)
    • commands:write (slash commands)
    • apps:read (app info)
    • users:read (user info)

3. Install App

  • Get your Bot User OAuth Token (starts with xoxb-)
  • Install app to your workspace

4. Configure TruthVouch

Configure your Slack integration via the TruthVouch web dashboard or use the REST API:

Terminal window
curl -X POST https://api.truthvouch.com/api/v1/integrations/slack \
-H "Authorization: Bearer tv_live_..." \
-H "Content-Type: application/json" \
-d '{
"token": "xoxb-your-token"
}'

Alternatively, set via environment variable:

Terminal window
export SLACK_BOT_TOKEN=xoxb-your-token

Features

Alert Notifications

Receive alerts in Slack channels via REST API:

Terminal window
curl -X POST https://api.truthvouch.com/api/v1/integrations/slack/rules \
-H "Authorization: Bearer tv_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Hallucination Alerts",
"trigger": "confidence < 0.7",
"channel": "#ai-governance",
"mention": "@ops"
}'

SDK integration coming Q2 2026. See SDKs Overview for details.

Slash Commands

Query verification directly from Slack:

/truthvouch verify "Is the Earth flat?"
/truthvouch policy list
/truthvouch kb search "OpenAI"
/truthvouch audit last 24h

Interactive Message Buttons

from slack_sdk import WebClient
from slack_sdk.models.blocks import ActionsBlock, ButtonElement
client = WebClient(token="xoxb-your-token")
# Send message with actions
client.chat_postMessage(
channel="#alerts",
blocks=[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Potential hallucination detected in AI response"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Claim:* The Earth is flat\n*Confidence:* 5%"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "Acknowledge"},
"action_id": "acknowledge_alert"
},
{
"type": "button",
"text": {"type": "plain_text", "text": "Review Full Details"},
"action_id": "review_alert"
},
{
"type": "button",
"text": {"type": "plain_text", "text": "Suppress Rule"},
"action_id": "suppress_rule"
}
]
}
]
)

Advanced Configuration

Custom Slash Command Handler

from flask import Flask, request
from slack_sdk import WebClient
from slack_sdk.signature import SignatureVerifier
from truthvouch.client import TruthVouchClient
app = Flask(__name__)
slack_client = WebClient(token="xoxb-your-token")
tv_client = TruthVouchClient(api_key="your-api-key")
verifier = SignatureVerifier(signing_secret="your-signing-secret")
@app.route("/slack/commands", methods=["POST"])
def handle_slash_command():
# Verify request
if not verifier.is_valid_request(request.get_data(), request.headers):
return {"error": "Invalid request"}, 403
command_data = request.form
# Route by command
if command_data["command"] == "/truthvouch":
args = command_data["text"].split()
action = args[0] if args else "help"
if action == "verify":
text = " ".join(args[1:])
return handle_verify_command(text, command_data)
elif action == "policy":
return handle_policy_command(args[1:], command_data)
else:
return send_help(command_data)
return {"error": "Unknown command"}, 400
def handle_verify_command(text: str, command_data: dict) -> dict:
"""Handle /truthvouch verify command."""
# Show loading state
slack_client.chat_postEphemeral(
channel=command_data["channel_id"],
user=command_data["user_id"],
text="Verifying...:hourglass:"
)
# Perform verification
result = tv_client.evaluate_output(text=text)
# Build response
color = "good" if result.confidence > 0.7 else "danger"
confidence_text = f"{result.confidence:.0%}"
slack_client.chat_postMessage(
channel=command_data["channel_id"],
blocks=[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*Verification Result*\n```{text}```"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": f"*Confidence*\n{confidence_text}"
},
{
"type": "mrkdwn",
"text": f"*Status*\n{'✓ Verified' if result.confidence > 0.7 else '✗ Uncertain'}"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*Sources:*\n" + "\n".join([
f"• <{c['url']}|{c['title']}>"
for c in result.citations[:3]
])
}
}
]
)
return {"response_type": "in_channel"}
@app.route("/slack/actions", methods=["POST"])
def handle_actions():
"""Handle button clicks and other interactions."""
payload = json.loads(request.form["payload"])
action = payload["actions"][0]["action_id"]
user_id = payload["user"]["id"]
channel_id = payload["channel"]["id"]
if action == "acknowledge_alert":
slack_client.chat_postMessage(
channel=channel_id,
text=f"<@{user_id}> acknowledged the alert"
)
elif action == "review_alert":
slack_client.chat_postMessage(
channel=channel_id,
text=f"<@{user_id}> is reviewing the alert"
)
return {}

Alert Routing

Route alerts to different channels by severity:

from truthvouch.client import TruthVouchClient
tv_client = TruthVouchClient(api_key="your-api-key")
# Configure alert rules for different channels
# (see alert configuration in the SDK docs for routing alerts by severity)

Thread Conversations

Keep related alerts in conversation threads:

from slack_sdk import WebClient
client = WebClient(token="xoxb-your-token")
# Post initial alert
response = client.chat_postMessage(
channel="#alerts",
text="Hallucination detected"
)
thread_ts = response["ts"]
# Follow up with details in thread
client.chat_postMessage(
channel="#alerts",
thread_ts=thread_ts,
text="Updated confidence: 32% (was 45%)"
)
# Ask for review in thread
client.chat_postMessage(
channel="#alerts",
thread_ts=thread_ts,
text="Awaiting human review..."
)

Workflows and Automation

Create Slack Workflow

Slack Workflows can integrate TruthVouch:

  1. Go to Workspace Settings → Workflows
  2. Create new workflow triggered by message
  3. Add step to call TruthVouch API
  4. Process verification result
  5. Send notification

Workflow Template

name: "Verify Message Content"
trigger: "message"
steps:
- name: "Extract message text"
action: "extract_text"
input: "{{message.text}}"
- name: "Call TruthVouch"
action: "http_request"
url: "https://api.truthvouch.com/api/v1/shield/verify"
method: "POST"
headers:
Authorization: "Bearer {{env.TRUTHVOUCH_API_KEY}}"
body:
text: "{{message.text}}"
- name: "Check confidence"
condition: "response.confidence < 0.7"
then:
- name: "Post warning"
action: "post_message"
channel: "#alerts"
text: "⚠️ Unverified claim: {{message.text}}"

Monitoring and Analytics

Track Slack integration health using your monitoring system or the TruthVouch dashboard. Monitor command execution and alert delivery through your webhook integration.

Security

Signing Secrets

Verify all requests come from Slack:

from slack_sdk.signature import SignatureVerifier
verifier = SignatureVerifier(
signing_secret="your-signing-secret"
)
@app.route("/slack/events", methods=["POST"])
def verify_request():
if not verifier.is_valid_request(
body=request.get_data(),
headers=request.headers
):
return {"error": "Unauthorized"}, 403

Token Management

Never hardcode tokens:

import os
from dotenv import load_dotenv
load_dotenv()
token = os.getenv("SLACK_BOT_TOKEN")
signing_secret = os.getenv("SLACK_SIGNING_SECRET")
if not token or not signing_secret:
raise ValueError("Missing Slack credentials")

Troubleshooting

Q: Commands not triggering

  • Verify bot has commands:write scope
  • Check command routing configuration
  • Test with curl first

Q: Slow response times

  • Cache verification results
  • Use async/await to avoid blocking
  • Check rate limits (120 requests/minute for Slack)

Q: Alerts not appearing

  • Verify channel exists and bot is member
  • Check notification settings
  • Test webhook connectivity

Next Steps