Custom action
Call any API you own from inside a conversation. Define the method, URL, headers, and body with template variables, choose auto or confirm execution, and rely on built-in SSRF protection to keep requests safe.
View as MarkdownA custom action lets your agent call any HTTP API you control. You define the request — method, URL, headers, and body — using template variables that the model fills in from the conversation. Bookbag makes the call, captures the response, and hands it back to the agent to use in its reply.
This is the most powerful action type. Use it for anything not covered by a built-in or connector: your own order system, an internal lookup service, a CRM endpoint, or a webhook into another tool.
How it works
- 1Define parametersWrite a JSON Schema describing the arguments the model supplies (for example an order number or email).
- 2Build the request templateSet the method, URL, headers, and body. Reference parameters with
{{param}}placeholders — they are interpolated at call time. - 3Choose execution modeRead-only lookups can run in
auto; anything that writes should stay inconfirm(the default). - 4Test itRun the action with sample parameters to confirm the request, response shape, and confirm gate behave as expected.
Template variables
Use {{paramName}} anywhere in the URL, header values, or body. Each placeholder is replaced with the matching parameter the model supplied. A missing parameter resolves to an empty string rather than erroring.
{
"type": "object",
"properties": {
"order_number": { "type": "string", "description": "The customer's order number" },
"email": { "type": "string", "description": "Email on the order" }
},
"required": ["order_number"]
}Configuration example
A custom action's config holds the HTTP template. Here is a complete example that looks up an order from your own API:
{
"method": "GET",
"url": "https://api.yourstore.com/orders/{{order_number}}?email={{email}}",
"headers": {
"Authorization": "Bearer YOUR_API_KEY",
"Accept": "application/json"
}
}For a POST or PUT, add a body. A string body is interpolated for {{param}} placeholders; an object body is sent as JSON. When you send a body and don't set a Content-Type, Bookbag defaults it to application/json.
{
"method": "POST",
"url": "https://api.yourstore.com/returns",
"headers": { "Authorization": "Bearer YOUR_API_KEY" },
"body": {
"order": "{{order_number}}",
"reason": "{{reason}}"
}
}The agent receives the response as { http_status, ok, data }, where data is the parsed JSON (or truncated text if the response isn't JSON). Keep responses focused — return just the fields the agent needs to answer.
Security: SSRF protection
Every custom-action URL is checked before the request is made. Bookbag resolves the hostname via DNS and verifies every resolved IP. Requests to private, loopback, link-local, or cloud-metadata addresses are rejected — this prevents server-side request forgery (SSRF) against internal infrastructure.
Specifically, the following are blocked and will fail the action with a clear error:
| Blocked | Examples |
|---|---|
| Non-HTTP(S) protocols | file://, ftp://, gopher:// |
| Loopback | localhost, 127.0.0.0/8, ::1 |
| Private ranges | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 |
| Link-local & metadata | 169.254.0.0/16 (incl. 169.254.169.254), metadata.google.internal |
| IPv6 unique-local / link-local | fc00::/7, fe80::/10 |
Because hostnames are resolved and checked, a public domain that points at a private IP is blocked too. Your API must be reachable on a genuinely public address.
The confirm gate
Custom actions default to confirm execution mode. When the model calls a confirm-mode action, Bookbag does not fire the request immediately — it returns a confirm_required response with a one-time token. The request runs only when that token is confirmed, and is discarded if denied.
Leave anything that creates, updates, cancels, or charges in confirm mode. Reserve auto for safe, read-only lookups like fetching order status.