Why Slack + Odoo?
Your team lives in Slack. Instead of checking Odoo for updates, push critical events to Slack channels: new orders, large deals, overdue payments, low inventory, and support escalations. Teams respond faster when notifications arrive where they already work.
Integration Methods
| Method | Complexity | Capability |
|---|---|---|
| Slack Incoming Webhooks | Easy | One-way: Odoo → Slack |
| Slack Bot (API) | Medium | Two-way: Odoo ↔ Slack |
| Zapier/Make | Easy | No-code automation |
| Community Module | Easy | Pre-built Odoo module |
Method 1: Incoming Webhooks (Simplest)
Step 1: Create Slack Webhook
- Go to api.slack.com/apps → Create New App
- Select "From scratch" → name it "Odoo Alerts"
- Features → Incoming Webhooks → Activate
- Add New Webhook to Workspace → select channel (e.g., #sales-alerts)
- Copy the Webhook URL
Step 2: Create Odoo Server Action
# Server Action → Execute Code
import json
import requests
SLACK_WEBHOOK = "https://hooks.slack.com/services/T.../B.../xxx"
for rec in records:
message = {
"text": f":tada: New Sale Order!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*New Order: {rec.name}*\n"
f"Customer: {rec.partner_id.name}\n"
f"Amount: ${rec.amount_total:,.2f}\n"
f"Salesperson: {rec.user_id.name}"
}
}
]
}
requests.post(SLACK_WEBHOOK, json=message, timeout=5)Step 3: Create Automated Action
# Settings → Technical → Automated Actions
# Model: Sale Order
# Trigger: On Update
# Watch Field: state
# Before Update Filter: state = 'draft'
# Filter: state = 'sale' (confirmed)
# Action: Execute the server action aboveNotification Examples
New Large Order (> $5,000)
# Filter: [('amount_total', '>', 5000), ('state', '=', 'sale')]
message = f":moneybag: Large order confirmed!\n"
f"*{rec.name}* — ${rec.amount_total:,.2f}\n"
f"Customer: {rec.partner_id.name}"Overdue Invoice Alert
# Scheduled action (daily cron)
overdue = env['account.move'].search([
('move_type', '=', 'out_invoice'),
('payment_state', '!=', 'paid'),
('invoice_date_due', '<', datetime.date.today()),
])
if overdue:
total = sum(overdue.mapped('amount_residual'))
message = f":warning: {len(overdue)} overdue invoices!\n"
f"Total outstanding: ${total:,.2f}\n"
f"Oldest: {overdue[-1].name} ({overdue[-1].partner_id.name})"
requests.post(SLACK_WEBHOOK, json={"text": message}, timeout=5)Low Inventory Alert
# Cron: check stock levels daily
low_stock = env['product.product'].search([
('type', '=', 'product'),
('qty_available', '<', 10),
('qty_available', '>', 0),
])
if low_stock:
items = "\n".join([f"• {p.name}: {p.qty_available} left" for p in low_stock[:10]])
message = f":package: Low stock alert!\n{items}"
requests.post(SLACK_WEBHOOK, json={"text": message}, timeout=5)Support Ticket Escalation
# Trigger: Helpdesk ticket priority changed to 'Urgent'
message = f":rotating_light: Urgent ticket!\n"
f"*{rec.name}*\n"
f"Customer: {rec.partner_id.name}\n"
f"Assigned: {rec.user_id.name or 'Unassigned'}\n"
f"Description: {rec.description[:200]}..."Channel Strategy
| Channel | Notifications |
|---|---|
| #sales-alerts | New orders, large deals, lost opportunities |
| #finance-alerts | Overdue invoices, payment received, refund processed |
| #inventory-alerts | Low stock, stock-out, delivery issues |
| #support-escalations | Urgent tickets, SLA breaches |
| #deployments | New instance deployed, backup completed, errors |
Best Practices
- Don't over-notify — Only push critical/actionable events. Noisy channels get muted.
- Use channels, not DMs — Channel notifications are transparent and create accountability.
- Include action links — Add Odoo URL to the notification so users can click through.
- Format messages — Use Slack Block Kit for structured, readable notifications.
- Handle errors — Wrap webhook calls in try/except to prevent Odoo errors on Slack downtime.
DeployMonkey + Slack
DeployMonkey includes built-in Slack notifications for deployment events, monitoring alerts, and AI agent actions. Configure your Slack webhook once, and DeployMonkey keeps your team informed.