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:
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:
export SLACK_BOT_TOKEN=xoxb-your-tokenFeatures
Alert Notifications
Receive alerts in Slack channels via REST API:
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 24hInteractive Message Buttons
from slack_sdk import WebClientfrom slack_sdk.models.blocks import ActionsBlock, ButtonElement
client = WebClient(token="xoxb-your-token")
# Send message with actionsclient.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, requestfrom slack_sdk import WebClientfrom slack_sdk.signature import SignatureVerifierfrom 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 alertresponse = client.chat_postMessage( channel="#alerts", text="Hallucination detected")
thread_ts = response["ts"]
# Follow up with details in threadclient.chat_postMessage( channel="#alerts", thread_ts=thread_ts, text="Updated confidence: 32% (was 45%)")
# Ask for review in threadclient.chat_postMessage( channel="#alerts", thread_ts=thread_ts, text="Awaiting human review...")Workflows and Automation
Create Slack Workflow
Slack Workflows can integrate TruthVouch:
- Go to Workspace Settings → Workflows
- Create new workflow triggered by message
- Add step to call TruthVouch API
- Process verification result
- 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"}, 403Token Management
Never hardcode tokens:
import osfrom 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:writescope - 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
- Review ChatOps Overview
- Explore Alert Channels
- Check Webhook Integration