Custom Agents
Build external AI agents that integrate with GudDesk.
Agents are external services that receive webhook events from GudDesk and act on conversations via the REST API. Each agent brings its own logic, LLM, and billing — GudDesk provides the data and actions.
How Agents Work
- Install — register your agent in a workspace (via the dashboard or API). GudDesk creates a webhook endpoint and a dedicated API key.
- Receive events — GudDesk sends webhook payloads to your agent's URL when conversations and messages happen.
- Act — your agent calls the GudDesk API to reply, tag, assign, or resolve conversations using the API key it received at install.
This is the same pattern used by gud-agent, the open-source reference implementation.
Architecture
┌─────────────┐ webhook POST ┌──────────────┐
│ GudDesk │ ──────────────────▶ │ Your Agent │
│ (Platform) │ │ (External) │
│ │ ◀────────────────── │ │
└─────────────┘ REST API calls └──────────────┘
(with API key)
Your agent is a web service at a public HTTPS URL. It can be written in any language and use any LLM provider.
Installing an Agent
Via the Dashboard
- Go to Settings > AI Agents
- Click Install Agent
- Enter a name, your agent's webhook URL, and select which events to subscribe to
- Click Install Agent
- Save the webhook signing secret and API key — they're shown only once
Via the API
curl -X POST https://guddesk.com/api/v1/agents \
-H "Authorization: Bearer gd_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "RefundBot",
"description": "Handles refund requests automatically",
"webhookUrl": "https://your-agent.com/webhook",
"events": {
"onMessageCreated": true,
"onConversationCreated": true
}
}'The response includes one-time credentials:
{
"data": {
"id": "clx...",
"name": "RefundBot",
"credentials": {
"webhookSecret": "a1b2c3...",
"apiKey": "gd_xyz789..."
}
}
}Receiving Webhooks
When subscribed events occur, GudDesk sends a POST request to your webhook URL:
{
"event": "message.created",
"data": {
"conversationId": "conv_123",
"messageId": "msg_456",
"type": "VISITOR",
"body": "I want a refund for order #1234",
"workspaceId": "ws_789"
},
"timestamp": "2025-01-15T10:30:00.000Z"
}Headers
| Header | Description |
|---|---|
X-GudDesk-Signature | HMAC SHA-256 signature: sha256=<hex> |
X-GudDesk-Event | Event name (e.g., message.created) |
X-GudDesk-Agent-Id | Your agent's ID in GudDesk |
Verifying Signatures
Verify the X-GudDesk-Signature header using your webhook secret:
import { createHmac } from "crypto";
function verifySignature(payload: string, secret: string, signature: string): boolean {
const expected = createHmac("sha256", secret).update(payload).digest("hex");
return signature === `sha256=${expected}`;
}Available Events
| Event | Description |
|---|---|
message.created | A visitor or agent sent a message |
conversation.created | A new conversation started |
conversation.closed | A conversation was resolved |
conversation.assigned | A conversation was assigned to a team member |
Acting via the API
Use the API key from installation to call the GudDesk API. The key is scoped to the workspace and has READ_WRITE permission.
Reply to a conversation
curl -X POST https://guddesk.com/api/agent/reply \
-H "Authorization: Bearer gd_xyz789..." \
-H "Content-Type: application/json" \
-d '{
"conversationId": "conv_123",
"body": "Your refund for order #1234 has been processed!",
"senderName": "RefundBot"
}'Update a conversation
curl -X PATCH https://guddesk.com/api/v1/conversations/conv_123 \
-H "Authorization: Bearer gd_xyz789..." \
-H "Content-Type: application/json" \
-d '{
"status": "CLOSED",
"tags": ["refund", "resolved"]
}'Read conversation messages
curl "https://guddesk.com/api/v1/conversations/conv_123/messages" \
-H "Authorization: Bearer gd_xyz789..."Example: Simple Echo Agent
A minimal agent in Node.js that echoes back visitor messages:
import express from "express";
import { createHmac } from "crypto";
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!;
const API_KEY = process.env.GUDDESK_API_KEY!;
const GUDDESK_URL = process.env.GUDDESK_URL || "https://guddesk.com";
app.post("/webhook", async (req, res) => {
// Verify signature
const signature = req.headers["x-guddesk-signature"] as string;
const expected = `sha256=${createHmac("sha256", WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest("hex")}`;
if (signature !== expected) {
return res.status(401).send("Invalid signature");
}
const { event, data } = req.body;
// Only respond to visitor messages
if (event === "message.created" && data.type === "VISITOR") {
await fetch(`${GUDDESK_URL}/api/agent/reply`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
conversationId: data.conversationId,
body: `Echo: ${data.body}`,
senderName: "EchoBot",
}),
});
}
res.status(200).send("OK");
});
app.listen(3001);Best Practices
- Verify webhook signatures — always check the
X-GudDesk-Signatureheader - Respond quickly — return a 200 status within a few seconds; do heavy processing asynchronously
- Start simple — build agents for one specific task, not general-purpose bots
- Always have an escalation path — if your agent can't handle something, leave the conversation open for a human
- Use
senderName— identify your agent's replies so humans know which bot responded
Next Steps
- API Overview — Full REST API documentation
- Webhooks — Webhook event reference and payload format
- gud-agent — Open-source AI support agent reference implementation