Recipe: post runs into Lark or Slack
Vuon doesn't integrate with every chat product — instead, a tiny bridge you host turns webhook events into messages for whatever your team uses. This recipe forwards run results to a Lark custom-bot URL; the Slack variant differs by two lines.
Prerequisites
- A Lark custom bot in your target group chat (Group settings → Bots → Add bot → Custom bot). Copy its webhook URL, e.g.
https://open.larksuite.com/open-apis/bot/v2/hook/.... For Slack, create an incoming webhook instead. - A Vuon webhook endpoint pointing at your bridge, and its signing secret.
The bridge
With verifyWebhook from Verifying signatures in scope:
bridge.ts
import express from 'express';
const app = express();
const LARK_BOT_URL = process.env.LARK_BOT_URL!;
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
const rawBody = req.body.toString('utf8');
const ok = verifyWebhook({
secret: process.env.VUON_WEBHOOK_SECRET!,
rawBody,
timestampHeader: req.header('vuon-webhook-timestamp') ?? '',
signatureHeader: req.header('vuon-webhook-signature') ?? '',
});
if (!ok) {
return res.status(401).send('invalid signature');
}
const event = JSON.parse(rawBody);
const { title, summary, imageUrl, chatUrl, failureReason } = event.data;
const lines =
event.type === 'automation.run.completed'
? [`✅ ${title ?? 'Automation run'} finished`, summary, imageUrl, chatUrl]
: [`❌ ${title ?? 'Automation run'} failed`, failureReason, chatUrl];
await fetch(LARK_BOT_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
msg_type: 'text',
content: { text: lines.filter(Boolean).join('\n') },
}),
});
res.status(200).send('ok');
});
app.listen(3000);
Slack variant
Slack incoming webhooks take { "text": "..." } instead of Lark's msg_type/content envelope:
Slack payload
await fetch(SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: lines.filter(Boolean).join('\n') }),
});
Tips
- Respond 200 before slow work. Vuon times out after 10 seconds. If your bridge does more than a single forward call, acknowledge first and process in the background.
- Deduplicate on
vuon-webhook-idif a duplicate message in chat would be disruptive — delivery is at-least-once. - Lark unfurls
imageUrlandchatUrlautomatically in most clients; for richer layouts, switchmsg_typetointeractiveand build a card.