Skip to content
Instructions and actions9 min read

HTTP connectors

A Custom API action calls an endpoint you configure during a chat and answers with the result. The chatbot fills in the values.

Browse topics

What it is

Custom API — the HTTP request action type — lets your chatbot call an API during a conversation and answer with what comes back. In the type picker it reads "Call your API and answer with the result."

It is the most powerful action type and the only one, alongside MCP, that brings data back into the reply. The chatbot can look up an order, quote a live price, check a booking slot, or create a ticket, and then talk about the result in its own words.

You configure the request; the chatbot fills in the parts that come from the conversation. It can never change where the request goes.

When you would use it

  • Live data no knowledge base can hold: order status, stock levels, prices, delivery estimates, appointment availability.
  • Creating a record in a system you run: a ticket, a lead, a booking, a draft order.
  • Posting to a webhook: Slack, Discord, Teams, Zapier, Make.

If the service you want is a well-known one, start from a template rather than building it by hand — the address, headers, body, and credential style are already correct. See Use a preset and the Call action preset reference.

Where to find it

Open Dashboard → Chatbots → your chatbot → Actions, select New action, then Custom API under Start from scratch.

Steps

  1. Open the Actions tab and select New action → Custom API.
  2. On Details, set a Name and write When should the AI use this? — the field that decides whether the action fires at the right time.
  3. On Configure, choose the Method: GET, POST, PUT, PATCH, or DELETE.
  4. Enter the URL. It must be a public https:// address. Use {{placeholder}} for values that come from the conversation.
  5. Choose Authentication and paste the secret. Secrets are write-only.
  6. Add any Custom headers the API requires — an API version header, an Accept header. These are fixed values sent with every request.
  7. For POST, PUT, and PATCH, write the Request body as JSON, using the same {{placeholder}} style.
  8. Add one parameter row per placeholder, with a clear description so the model knows what to put there.
  9. Save, then use the Test tab. It shows the request that would be sent, with secrets masked, and never contacts the real endpoint.
  10. Turn on Enabled and try it in Test Chatbot, then read the run log.

The fields, in detail

Method and URL

Placeholders are written {{name}} and are substituted into the path and query string only. The scheme and host are fixed by you at save time:

https://api.example.com/v1/orders/{{order_id}}?include=shipping

That constraint is deliberate and is the core of the security model here. Whatever a visitor types, whatever an API returns, the request goes to the host you configured. A value can never repoint it.

Values are properly encoded as they are inserted, so an order number with a space or a slash in it cannot break the address.

Authentication

Four options, matching what most APIs offer:

OptionWhat you supplyHow it is sent
NoneNothingNo credential header. Right for webhook URLs, which are themselves the secret.
Bearer tokenOne tokenAn Authorization header with your token.
Basic authUsername and passwordAn encoded Authorization header. Many APIs use this with a key as the username.
API key headerA header name and a keyYour key in the header you name, for example X-API-Key.

Whatever you paste is stored encrypted and never returned to the browser. Once saved, the field shows a "stored" hint; leave it blank when editing to keep the existing secret, and fill it in only to rotate.

Custom headers

Static headers sent with every request — an API version header, an Accept header, a tenant header your service expects. Values are fixed and do not accept placeholders.

Request body

Available on POST, PUT, and PATCH. Write JSON, and use {{placeholder}} where a value comes from the conversation:

{
    "ticket": {
        "subject": "{{subject}}",
        "comment": { "body": "{{description}}" },
        "requester": { "name": "{{name}}", "email": "{{email}}" }
    }
}

Values are escaped as they are inserted, so a visitor typing a quotation mark or a newline cannot break out of the JSON string or restructure your request.

A body with no Content-Type header of your own is sent as JSON.

Parameters

One row per placeholder. Each has a Name (matching the placeholder exactly), a Type — string, integer, number, or boolean — a Description (helps the AI fill it), and a Required switch. You can also give a comma-separated list of allowed values to restrict a parameter to a fixed set.

The description is what the model reads while filling the value. The order number the visitor gave, digits only fills reliably; order id does not.

Worked example: quote a live price

The shape most people need first. Assume your catalogue exposes a public read-only search endpoint.

Details

  • Name: Look up a product price
  • When should the AI use this?: When the visitor asks the price, stock or details of a specific product and names the product.
  • Requires confirmation: off — nothing is changed.

Configure

  • Method: GET
  • URL: https://api.example.com/v1/products?search={{query}}&limit=3
  • Authentication: API key header, header name X-API-Key, key pasted in.
  • Parameters:
NameTypeRequiredDescription
querystringYesThe product name or keyword the visitor asked about.

Test. Sample message: "how much is the 12-inch cast iron pan?" You should see the action would trigger, query resolved to something like 12-inch cast iron pan, and a request preview pointing at your host.

Enable, then ask the same in Test Chatbot. The chatbot reads the response and answers in prose — it does not dump raw JSON at the visitor.

To turn this into a write action — creating an order rather than reading a price — change the method to POST, add a JSON body with placeholders, add a parameter row for each, and leave Requires confirmation on.

What comes back to the chatbot

The response body is fed back into the reply, capped in size so an enormous payload cannot swamp the conversation. The chatbot summarises it in the visitor's language.

Design your endpoint with that in mind. A response with three relevant fields produces a much better answer than one with ninety. If you control the API, add a fields or include parameter and use it in the URL — the templates for large platforms do exactly this.

The visitor never sees the raw response, the URL, or your credentials. In the run log you see a client-safe summary: the method, the host, the status code, and a truncated snippet.

Safety and what gets blocked

  • Public addresses only. Requests to private, internal, loopback, or reserved addresses are refused and recorded as Blocked destination. This holds even if a hostname resolves to a private address, so a public-looking name pointing inward will not work. Put the API on a genuinely public HTTPS hostname.
  • Fixed host. Conversation values never reach the scheme or host.
  • Time budget. Each call has a few seconds to respond. A slow endpoint is recorded as Timed out rather than blocking the reply.
  • Rate ceilings. There are per-minute and per-day ceilings per chatbot and a per-visitor cap. A well-behaved integration never notices them; a runaway loop does.
  • Circuit breaker. After repeated failures against the same endpoint, calls are paused briefly and recorded as Temporarily paused instead of being retried into the ground.
  • Confirmation on writes. POST, PUT, PATCH, and DELETE are treated as changing data and require the visitor to confirm on a following message before anything fires.
  • No double-firing. A retried or regenerated reply cannot run the same change twice — the earlier outcome is replayed instead. That is what stops a refreshed page creating two tickets.

What you will see

The Configure tab is a structured form — method, URL, auth, headers, body, parameters — not a free-text script box. The What you'll need panel at the top gives the setup steps for the type or the template you started from.

In the run log you get one row per attempt with a status and, on failures, a plain-language reason such as Blocked destination, Upstream error, Unreachable, Timed out, or Rate limited. Open a row for the arguments, the request summary, and the response snippet. See Call Action history.

Limits and plan notes

  • A Custom API action counts as one enabled Call Action: Free 0, Starter 3, Standard 8, Pro 12, Agency 20 per chatbot. See Plans and what you get.
  • You need permission to manage actions on that chatbot. See Roles and permissions.
  • Only http and https addresses are accepted, and in practice you want HTTPS — many services reject credentials over plain HTTP anyway.
  • Response size is capped, and each call is time-boxed.
  • Agentency does not retry a failed call on its own. The chatbot tells the visitor it could not do that right now, and the failure is in your run log.
  • This is not the same thing as the developer API you use to talk to Agentency. That is documented under API host and no prefix.

Common problems

Test says Blocked destination.

The host is private, internal, or otherwise not reachable from the public internet — or you left a placeholder like your-store.com in the address. Fix the address; there is no allowlist you can add a private host to from the dashboard.

Every call returns 401 or 403.

The credential or its scope. Confirm the auth style matches what the API expects — several services want the key as the Basic-auth username rather than the password — and that the token has the permission for this operation.

The call succeeds but the chatbot answers vaguely.

The response is too large or too noisy. Trim it with a fields or include parameter, or point at a narrower endpoint.

The API never receives anything from real visitors.

Check that the action is Enabled, the chatbot is active, and there is not a run sitting at Awaiting confirmation — a high-risk action waits for the visitor's next message before it fires.

Runs read Timed out.

Your endpoint is slower than the per-call budget. Make it faster, or move the slow work behind a queue and have the endpoint return immediately.

It worked yesterday and fails today.

Read the run log error. An expired token, a rotated key, or a provider version change are the usual causes; Temporarily paused means the endpoint failed repeatedly and calls were briefly suspended.

Common questions

Can the chatbot change where the request is sent?

No. You fix the scheme and host at save time. Values from the conversation fill the path, query and body only.

Can I call an API on my own network?

No. Private, internal and reserved addresses are refused and logged as Blocked destination. Use a public HTTPS hostname.

Is this the same as the MCP connector?

No. A Custom API action is a single request you configure yourself. MCP is a separate type that is usually unavailable.

What happens if my endpoint is slow?

Each call is time-boxed. Past the budget the run is recorded as Timed out and the chatbot tells the visitor it could not do that.

Could a retried reply create two orders?

No. A repeat of the same change replays the recorded outcome instead of firing the side effect again.

Was this article helpful?

Ready to try it on your own content?

Create a free workspace, add a document, and ask the questions your team is tired of answering.