Integrations
Custom Agent Tools
Give the AI live access to your systems: define tools the LLM can call during reply generation to fetch order status, look up accounts, check inventory, and more.
Quick facts#
| Tool types | SERVER_SIDE (HTTP call from HelpStack) or CLIENT_SIDE (run in the visitor's browser) |
| Managed via | Dashboard + /api/agent-tools (org-level), /api/channels/[id]/agent-tools (channel-level) |
| Auth | Dashboard session (these are configured by your team) |
| Server tool timeout | ~10s, response capped at ~10 KB |
| Client tool timeout | ~5s (socket round-trip) |
| Logging | Every call recorded in ToolCallLog |
For the conceptual overview, see the Agent tools guide. This page is the technical reference.
Tool anatomy#
A tool definition has these fields:
| Field | Required | Notes |
|---|---|---|
| Name | yes | The function name the LLM calls, e.g. get_order_status. Must be a valid function identifier |
| Description | yes | The LLM reads this to decide when to call the tool. Max ~2000 chars (validated). Be specific |
| URL | yes (server-side) | Must be HTTPS. SSRF-protected: a blocklist rejects internal/private network targets |
| Method | no | GET | POST | PUT | PATCH. Default POST |
| Headers | no | Optional JSON object. Can be encrypted/masked (use for API keys/tokens) |
| Parameters Schema | yes | A JSON Schema object describing the arguments the LLM fills in (parametersSchema) |
| Type | yes | SERVER_SIDE or CLIENT_SIDE |
| Active | — | Toggle to enable/disable the tool without deleting it |
Worked example — get_order_status (SERVER_SIDE)#
Tool definition
| Field | Value |
|---|---|
| Name | get_order_status |
| Type | SERVER_SIDE |
| Method | POST |
| URL | https://api.YOURCOMPANY.com/orders/status |
| Headers | { "Authorization": "Bearer YOUR_API_TOKEN" } (store as encrypted header) |
| Description | Look up the current status and tracking info for a customer order by its order number. Call this whenever the customer asks where their order is, when it will arrive, or to confirm an order was placed. |
Parameters schema (JSON Schema)
{
"type": "object",
"properties": {
"order_number": {
"type": "string",
"description": "The customer's order number, e.g. ORD-10432"
}
},
"required": ["order_number"]
}
Request your endpoint receives
On a tool call, HelpStack sends the LLM-provided arguments as the request body (for POST/PUT/PATCH), with your configured headers plus Content-Type: application/json:
POST /orders/status HTTP/1.1
Host: api.YOURCOMPANY.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
{ "order_number": "ORD-10432" }
Response contract your endpoint must honor
Return JSON the model can read. Keep it small — responses are capped at ~10 KB and the call times out at ~10s.
{
"status": "shipped",
"carrier": "DHL",
"tracking_number": "JD0140...",
"estimated_delivery": "2026-06-02"
}
The AI receives this payload as the tool result and weaves it into its reply. There is no required envelope — return whatever fields are useful, but make them self-describing so the model uses them correctly.
Writing good descriptions#
The description is the single most important field — it is the only thing the LLM uses to decide whether and when to call the tool.
- State what the tool returns and when to call it ("Call this when the customer asks ...").
- Mention the trigger phrases customers actually use.
- Describe each parameter clearly in its schema
description. - Keep under the ~2000 char limit (the save dialog validates and surfaces errors).
Security & SSRF protection#
- HTTPS only. Plain HTTP URLs are rejected.
- SSRF blocklist. Internal/private network targets (loopback, private RFC1918 ranges, link-local, metadata endpoints) are blocked so a tool cannot be pointed at internal infrastructure.
- Secret headers. Put API keys/tokens in Headers, which can be encrypted/masked rather than stored in plaintext.
- Treat the tool endpoint as internet-facing — authenticate requests (e.g. a bearer token in Headers) and validate input on your side.
Timeouts & caps#
| Server-side | Client-side | |
|---|---|---|
| Timeout | ~10s | ~5s |
| Response cap | ~10 KB | — |
| On failure/timeout | Logged; AI told the tool is unavailable and continues with the best reply it can |
Failures degrade gracefully — a broken or slow tool never blocks a reply; the AI simply proceeds without that data.
Org vs. channel tools + semantic filtering#
- Tools can be defined at the organization level and at the channel level.
- For a given conversation, org-level and channel-level tools are merged, and a channel tool overrides an org tool with the same name.
- The merged set is semantically filtered by relevance to the customer's query, so a large catalog of tools doesn't bloat every LLM call — only relevant tools are offered.
- Selected tools are converted to OpenAI/Anthropic function definitions and offered during reply generation.
OpenAPI import#
You can bootstrap tools from an existing API: paste or upload an OpenAPI 3.0 spec, and HelpStack extracts its operations into tool definitions you review and save. This is the fastest way to expose an existing REST API to the AI.
Logging#
Every tool call is recorded in ToolCallLog. View a tool's call history (arguments, outcome, timing) via:
GET /api/agent-tools/[id]/logs
Use the logs to debug why a tool was or wasn't called, and to spot timeouts/errors.
Client-side tools (advanced)#
CLIENT_SIDE tools are declared the same way (name, description, parameters schema) but execute in the website visitor's browser, mediated by the widget socket:
- The AI emits a tool call for a
CLIENT_SIDEtool. - The server emits
tool:executeto the widget. - The widget runs it and replies with
tool:result(ortool:error). - There is a ~5s timeout; on timeout the call degrades gracefully (tool unavailable).
There is no public JS API to register client-side tool handlers in the widget loader today. Client-side execution is server/iframe-mediated — treat it as an advanced capability and do not expect a
registerTool()-style snippet on your page. See Widget Embed.