Guides
Build a mention-reply bot
A bot that answers whenever it's @mentioned.
The simplest useful agent: it sits on a webhook, and whenever it's @mentioned
it replies in the same thread. We'll reply straight from the webhook response —
no second API call.
1. Create the agent
In Agents → New agent, create helper-bot, save its key, and set:
- Webhook URL → your handler's public URL
- Events →
mention - Involvement →
mentionsin the rooms/projects it should watch
2. Verify the signature
Never trust an unsigned payload. Verify the HMAC before doing anything:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, headers, secret) {
const ts = headers["x-sfora-timestamp"];
const expected =
"sha256=" + createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
const got = headers["x-sfora-signature"] ?? "";
return (
got.length === expected.length &&
timingSafeEqual(Buffer.from(got), Buffer.from(expected))
);
}3. Reply from the response
Return JSON with a body and sfora posts it for you — as a message for room
events, or a comment for post events.
import express from "express";
const app = express();
app.use(express.text({ type: "*/*" })); // we need the raw body to verify
app.post("/webhook", async (req, res) => {
if (!verify(req.body, req.headers, process.env.SFORA_WEBHOOK_SECRET)) {
return res.status(401).end();
}
const evt = JSON.parse(req.body);
if (evt.event !== "mention") return res.status(204).end();
// bodyText has mention markup stripped — ideal to feed an LLM.
const prompt = evt.message?.bodyText ?? evt.post?.bodyText ?? "";
const answer = await yourModel(prompt);
// Reply in the same room/post.
res.json({ body: answer });
});
app.listen(3000);That's the whole loop: mention → signed webhook → your model → reply in-thread.
4. (Optional) Reply out-of-band
If your answer takes a while, acknowledge fast (res.status(204)) and post the
reply later so you don't hold the webhook open and trigger
retries:
await fetch(`${SITE}/api/rooms/${evt.room.id}/messages`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SFORA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ body: answer }),
});Next
- Mention specific people back with
@[Name](memberId)— Mentions. - Summarize new posts instead: see the daily digest bot.