Creating Actions
Step-by-step guide to building custom actions for your Chatsby AI agent — from trigger definition to webhook implementation, testing, and monitoring.
Creating Custom Actions
Custom actions let your AI agent interact with external systems during live conversations. This guide covers everything you need to build, test, and deploy a custom action — from defining triggers to writing webhook handlers and debugging in the Playground.
Prerequisites
Before you begin, make sure you have the following ready:
- A Chatsby account on a paid plan (Pro, Business, or Enterprise). Custom actions are not available on the Free plan.
- An HTTP endpoint that can receive POST requests and return JSON responses. This can be a serverless function (AWS Lambda, Vercel, Cloudflare Workers), a dedicated server, or any platform that exposes an HTTPS URL.
- Basic understanding of webhooks. When your action triggers, Chatsby sends a POST request to your URL with the collected parameters. Your endpoint processes the request and returns a response that the agent delivers to the user.
- Authentication credentials (if your endpoint is protected). Chatsby supports Bearer tokens and custom headers.
If you do not have a backend ready, you can use services like Pipedream or Make to create a webhook endpoint without writing code. For testing, webhook.site lets you inspect incoming requests.
Step-by-Step Creation Guide
Navigate to the Actions Panel
From your agent's dashboard, click the Actions tab in the left sidebar. You will see your existing actions (including built-in ones) listed here.
Click Create Action in the top-right corner to open the action builder.
Name Your Action
Give your action a clear, descriptive name. This name is internal only — users will never see it. It appears in your dashboard and analytics.
Good names:
Order Status LookupAppointment Booking — DentalRefund Request Submission
Avoid vague names:
Action 1New actionTest
Define the Trigger Condition
The trigger condition is a natural-language description that tells the agent when this action should activate. The AI uses this description to match user intent, so clarity and specificity matter.
Write your trigger as if you are instructing a human colleague: "Activate this action when..."
Good trigger examples:
| Trigger Description | Why It Works |
|---|---|
| "When the user asks about the status of an order, wants to track a package, or asks where their shipment is" | Covers multiple phrasings of the same intent |
| "When the user wants to book, schedule, or reschedule an appointment with a doctor" | Specific to the domain and includes related verbs |
| "When the user requests a refund or wants to return a product they purchased" | Clear scope, two related intents grouped together |
Bad trigger examples:
| Trigger Description | Problem |
|---|---|
| "When the user asks a question" | Far too broad — would trigger on nearly every message |
| "Order" | Single keyword with no context — the agent cannot determine intent |
| "When the user is unhappy" | Subjective and ambiguous — what counts as "unhappy"? |
| "When the user asks about anything related to their account" | Too broad — could conflict with multiple actions |
Define Parameters
Parameters are the pieces of information the agent must collect from the user before the action can execute. For each parameter, configure the following:
| Field | Description | Required |
|---|---|---|
| Name | Internal identifier (e.g., order_id, email). Use snake_case, no spaces. | Yes |
| Type | The data type. See table below. | Yes |
| Description | Tells the agent what to ask for and how to describe it to the user. | Yes |
| Required | Whether the action can proceed without this parameter. | Yes |
| Validation | Additional rules (min/max for numbers, regex for text). | No |
Parameter Types
| Type | Description | Validation | Example Values |
|---|---|---|---|
| text | Free-form text input. Use for names, addresses, descriptions, and any unstructured input. | Optional regex pattern, min/max length | "John Smith", "123 Main St" |
| Email address. Chatsby validates format automatically. | Built-in email format validation | "[email protected]" | |
| number | Numeric value. Integers or decimals. | Optional min/max value | 42, 199.99 |
| phone | Phone number. Accepts international formats. | Built-in phone format validation | "+1 (555) 123-4567" |
| select | Predefined list of options. User must choose one. | Options list (define in configuration) | "standard", "express", "overnight" |
| date | Calendar date. Agent guides user to provide a parseable date. | Optional min/max date | "2026-04-15", "next Tuesday" |
Tips for parameter design:
- Only collect what your endpoint actually needs. Every additional parameter adds friction.
- Mark parameters as optional when reasonable. For example, a phone number for a support ticket might be helpful but not mandatory.
- Write descriptions from the user's perspective: "Your order confirmation number (starts with ORD-)" is better than "order_id field."
Configure the Webhook
Enter the details of the endpoint Chatsby should call when all parameters are collected.
| Setting | Description | Notes |
|---|---|---|
| Webhook URL | The HTTPS endpoint that receives the request | Must be HTTPS. HTTP is rejected. |
| Method | HTTP method | POST (fixed) |
| Headers | Custom headers sent with every request | Use for authentication, API keys, content type overrides |
| Authentication | Bearer token authentication | Token is sent as Authorization: Bearer <token> |
| Timeout | Maximum time to wait for a response | 15s (Pro), 30s (Business), 60s (Enterprise) |
| Fallback message | Message shown to the user if the webhook fails or times out | Default: "I'm sorry, I wasn't able to complete that request. Please try again." |
Authentication example:
If your endpoint requires a Bearer token, enter the token in the Authentication field. Chatsby will include it in the request headers:
Authorization: Bearer sk_live_abc123def456
Content-Type: application/json
X-Chatsby-Signature: sha256=a1b2c3d4...
Test in the Playground
Before activating your action, test it thoroughly in the Playground.
- Open the Playground from your agent's dashboard.
- Start a conversation that should trigger your action.
- Verify that the agent recognizes the trigger and begins collecting parameters.
- Confirm that each parameter is requested with clear, natural language.
- Check that the webhook receives the correct payload (use your server logs or webhook.site).
- Verify that the agent delivers the response correctly.
Debugging tips:
- If the action does not trigger, review your trigger description. It may be too narrow or conflicting with another action.
- If parameters are collected in the wrong order, the agent is optimizing for conversational flow. This is expected and usually results in a better user experience.
- If the webhook returns an error, the Playground will show the HTTP status code and response body in the debug panel.
Activate the Action
Once testing is complete, toggle the action status to Active in the action list. The action is immediately available in all deployed instances of your agent (widget, API, integrations).
You can deactivate an action at any time without deleting it. Deactivated actions are ignored by the agent.
Request Payload Format
When your action executes, Chatsby sends a POST request to your webhook URL with the following JSON payload:
{
"event": "action.executed",
"action_id": "act_8f3k2j1m",
"action_name": "Order Status Lookup",
"conversation_id": "conv_abc123",
"agent_id": "agent_xyz789",
"timestamp": "2026-04-02T14:30:00Z",
"parameters": {
"order_id": "ORD-78542",
"email": "[email protected]"
},
"metadata": {
"source": "website_widget",
"page_url": "https://acme.com/support",
"user_agent": "Mozilla/5.0 ...",
"ip_country": "US"
}
}Payload Fields Reference
| Field | Type | Description |
|---|---|---|
event | string | Always "action.executed" |
action_id | string | Unique identifier for the action configuration |
action_name | string | The name you gave the action |
conversation_id | string | Unique identifier for the current conversation |
agent_id | string | The agent that triggered the action |
timestamp | string | ISO 8601 timestamp of when the action was triggered |
parameters | object | Key-value pairs of collected parameters |
metadata | object | Contextual information about the conversation (source, page URL, user agent, inferred country) |
Response Format
Your endpoint must return a JSON response. Chatsby uses the response to formulate the agent's reply to the user.
Success Response
{
"status": "success",
"message": "Order ORD-78542 shipped on March 28th via FedEx. Tracking number: 7891234567. Estimated delivery: April 4th.",
"data": {
"tracking_url": "https://fedex.com/track/7891234567",
"carrier": "FedEx",
"estimated_delivery": "2026-04-04"
}
}| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | "success" or "error" |
message | string | Yes | The text the agent will use to respond to the user. Write this as you want the agent to say it. |
data | object | No | Additional structured data. The agent may reference this in its response if relevant. |
Error Response
{
"status": "error",
"message": "We couldn't find an order with that number. Please double-check your order confirmation email and try again.",
"error_code": "ORDER_NOT_FOUND"
}When your endpoint returns an error response, the agent delivers the message field to the user. Design error messages to be helpful and suggest next steps.
| HTTP Status | Behavior |
|---|---|
| 200 | Agent uses the message field from the response body |
| 4xx | Agent delivers the message from the response body if present, otherwise the fallback message |
| 5xx | Agent delivers the configured fallback message |
| Timeout | Agent delivers the configured fallback message |
Error Handling and Retry Logic
Chatsby does not automatically retry failed webhook calls. If your endpoint returns a 5xx error or times out, the agent delivers the fallback message and the conversation continues normally.
To build resilience:
- Implement retries in your backend if your action calls downstream services that may be temporarily unavailable.
- Return meaningful error messages with a
200status code and"status": "error"so the agent can communicate specific issues to the user (e.g., "order not found" vs. a generic failure). - Monitor your endpoint health. Use uptime monitoring (Pingdom, UptimeRobot, or your cloud provider's built-in tools) to catch outages early.
- Set appropriate timeouts. If your backend operation takes longer than the allowed timeout, consider returning an acknowledgment immediately and following up via email or notification.
Complete Example: Order Status Lookup
Here is a full end-to-end example of building an order status lookup action, including the webhook handler in Node.js.
Action Configuration
| Setting | Value |
|---|---|
| Name | Order Status Lookup |
| Trigger | "When the user asks about the status of an order, wants to track a package, asks where their shipment is, or wants to know when their order will arrive" |
| Parameters | order_id (text, required, description: "Your order number, usually starts with ORD-"), email (email, required, description: "The email address you used when placing the order") |
| Webhook URL | https://api.yourstore.com/webhooks/chatsby/order-status |
| Auth | Bearer token: sk_live_yourtoken123 |
Webhook Handler (Node.js / Express)
const express = require("express");
const app = express();
app.use(express.json());
app.post("/webhooks/chatsby/order-status", async (req, res) => {
// 1. Verify the request is from Chatsby
const signature = req.headers["x-chatsby-signature"];
if (!verifySignature(req.body, signature, process.env.CHATSBY_WEBHOOK_SECRET)) {
return res.status(401).json({
status: "error",
message: "Unauthorized request.",
});
}
// 2. Extract parameters
const { order_id, email } = req.body.parameters;
try {
// 3. Look up the order in your database
const order = await db.orders.findOne({
orderId: order_id,
customerEmail: email,
});
if (!order) {
return res.json({
status: "error",
message: `We couldn't find order ${order_id} associated with ${email}. Please double-check your order number and the email you used at checkout.`,
});
}
// 4. Format and return the response
const statusMessages = {
processing: `Order ${order_id} is being processed. It should ship within 1-2 business days.`,
shipped: `Order ${order_id} shipped on ${order.shippedDate} via ${order.carrier}. Tracking number: ${order.trackingNumber}. Estimated delivery: ${order.estimatedDelivery}.`,
delivered: `Order ${order_id} was delivered on ${order.deliveredDate}. It was left at: ${order.deliveryLocation}.`,
cancelled: `Order ${order_id} was cancelled on ${order.cancelledDate}. If you were charged, the refund should appear within 5-10 business days.`,
};
return res.json({
status: "success",
message: statusMessages[order.status] || `Order ${order_id} status: ${order.status}.`,
data: {
order_status: order.status,
tracking_url: order.trackingUrl || null,
carrier: order.carrier || null,
},
});
} catch (error) {
console.error("Order lookup failed:", error);
return res.status(500).json({
status: "error",
message: "Something went wrong while looking up your order. Please try again in a moment.",
});
}
});
app.listen(3000, () => console.log("Webhook server running on port 3000"));Complete Example: Appointment Booking
Action Configuration
| Setting | Value |
|---|---|
| Name | Book Appointment |
| Trigger | "When the user wants to book, schedule, or make an appointment, or asks about available times" |
| Parameters | full_name (text, required), email (email, required), phone (phone, optional), preferred_date (date, required, description: "When would you like to come in?"), service_type (select, required, options: "General Checkup", "Consultation", "Follow-up") |
| Webhook URL | https://api.yourclinic.com/webhooks/chatsby/book |
Webhook Handler (Node.js / Express)
app.post("/webhooks/chatsby/book", async (req, res) => {
const { full_name, email, phone, preferred_date, service_type } = req.body.parameters;
try {
// Check availability
const slot = await calendar.findAvailableSlot({
date: preferred_date,
serviceType: service_type,
duration: service_type === "General Checkup" ? 30 : 60,
});
if (!slot) {
// No availability — suggest alternatives
const alternatives = await calendar.getNextAvailable({
serviceType: service_type,
limit: 3,
});
const altText = alternatives
.map((s) => `${s.date} at ${s.time}`)
.join(", ");
return res.json({
status: "error",
message: `Unfortunately, there are no openings on ${preferred_date} for a ${service_type}. The next available times are: ${altText}. Would you like to book one of those instead?`,
});
}
// Book the appointment
const appointment = await calendar.book({
slot,
patient: { full_name, email, phone },
serviceType: service_type,
});
return res.json({
status: "success",
message: `Your ${service_type} appointment is confirmed for ${appointment.date} at ${appointment.time}. A confirmation email has been sent to ${email}. Please arrive 10 minutes early. To reschedule or cancel, reply to the confirmation email.`,
data: {
appointment_id: appointment.id,
date: appointment.date,
time: appointment.time,
},
});
} catch (error) {
console.error("Booking failed:", error);
return res.json({
status: "error",
message: "We ran into an issue while booking your appointment. Please call us at (555) 123-4567 to complete the booking.",
});
}
});Monitoring Action Performance
After deploying your actions, monitor their performance from the Actions tab in your agent dashboard. Chatsby tracks the following metrics for each action:
| Metric | Description |
|---|---|
| Total triggers | Number of times the action was activated |
| Successful executions | Webhook returned a success response |
| Failed executions | Webhook returned an error or timed out |
| Average response time | How long your webhook takes to respond |
| Parameter completion rate | Percentage of triggered actions where all required parameters were collected |
Use these metrics to identify:
- High failure rates — Indicates your endpoint may be unreliable or returning unexpected responses.
- Low completion rates — Suggests parameters are too complex, too numerous, or confusingly described. Consider simplifying.
- Slow response times — Optimize your backend or consider caching frequent lookups.
Best Practices and Common Pitfalls
Do
- Write specific trigger descriptions. Include multiple phrasings and synonyms to catch variations of the same intent.
- Minimize required parameters. Every additional required field increases the chance a user abandons the flow.
- Return user-friendly messages. Write your webhook responses as if you are speaking to the customer directly.
- Handle all error cases. Always return a helpful message, even when things go wrong.
- Test with the Playground before activating. Simulate edge cases: missing info, invalid input, typos.
- Use HTTPS exclusively. Chatsby rejects HTTP webhook URLs for security.
Avoid
- Overlapping triggers. If two actions have similar triggers, the agent may activate the wrong one. Make each trigger description distinct.
- Exposing sensitive data in responses. Do not return full credit card numbers, passwords, or internal system details in the
messagefield. - Long-running operations in the webhook. If your process takes more than a few seconds, return an acknowledgment and follow up asynchronously.
- Ignoring the fallback message. Customize it for each action instead of relying on the generic default.
- Skipping request verification. Always validate the
X-Chatsby-Signatureheader to ensure requests originate from Chatsby.
On this page
- Prerequisites
- Step-by-Step Creation Guide
- Request Payload Format
- Payload Fields Reference
- Response Format
- Success Response
- Error Response
- Error Handling and Retry Logic
- Complete Example: Order Status Lookup
- Action Configuration
- Webhook Handler (Node.js / Express)
- Complete Example: Appointment Booking
- Action Configuration
- Webhook Handler (Node.js / Express)
- Monitoring Action Performance
- Best Practices and Common Pitfalls
- Do
- Avoid