Skip to content
Developer API5 min read

API host — no /api prefix

Resources live at the root of the API host: call https://api.example.com/chatbots, never /api/chatbots.

Browse topics

What it is

Agentency runs on two hostnames, and the single most common integration bug is calling the wrong one:

  • The dashboard host — where you sign in. It serves HTML and it is not the API.
  • The API host — api. on the same domain. Everything you call from your own code lives here.

On the API host, resources start at the root. There is no /api prefix.

https://api.example.com/chatbots          ✅
https://api.example.com/api/chatbots      ❌ 404

If you have integrated with other products where /api/v1/... is the convention, this is the habit to unlearn. Some routes do carry a /v1 segment of their own — the knowledge ingest endpoint is /v1/knowledge/ingest — but that is part of the route, never an /api wrapper.

When you would use it

Read this the first time you point a script, a server job, or a plugin at Agentency, and again the moment a request returns a 404 that you cannot explain.

Where to find your API host

Three reliable ways, in order of convenience:

  1. The ingest reference. Open Dashboard → Settings → Developer. The Knowledge Ingest API card prints the full endpoint URL for your installation. Everything before /v1/knowledge/ingest is your API base.
  2. The widget snippet. Open Chatbots → your chatbot → Integrations → Web and copy the embed code. The data-api-base-url attribute is the same origin.
  3. Ask whoever runs your installation if you are on a self-hosted or white-labelled deployment.

Steps

  1. Copy the API base URL from one of the sources above. Strip any trailing slash.
  2. Build every request as {base}/{resource} — for example {base}/chatbots.
  3. Create a personal access token with the narrowest scopes your integration needs. See Create a personal access token.
  4. Send it as a bearer token in the Authorization header on every request.
  5. Send and accept JSON: Content-Type: application/json on writes, Accept: application/json throughout.
  6. Test one read call before you write any integration code. GET {base}/chatbots is the cheapest possible smoke test.
  7. Read the response envelope rather than only the status code — the body carries a machine-readable error.code when something is refused.

A first request

Read your chatbots. This requires a token with chatbots:read.

curl -s https://api.example.com/chatbots \
  -H "Authorization: Bearer $AGENTENCY_TOKEN" \
  -H "Accept: application/json"

Push a knowledge item. This requires knowledge:write, and it is the endpoint the Developer tab documents in full.

curl -X POST https://api.example.com/v1/knowledge/ingest \
  -H "Authorization: Bearer $AGENTENCY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "chatbot_id": 42,
        "name": "Returns policy",
        "content": "We accept returns within 30 days of delivery."
      }'

Replace api.example.com with your own API host and 42 with a real chatbot id from Dashboard → Chatbots.

What you will see

Responses are JSON with a consistent envelope: a success flag, a data payload on success, and a human-readable message. Failures add an error object carrying a stable code, a message, and a details object — switch your error handling on error.code, never on the message text, which is localised.

Codes you will meet early:

StatusMeaningFix
401Missing, malformed, expired, or revoked tokenCheck the Authorization header, then check the key still exists
403 insufficient_scopeThe token is valid but lacks the scope this route needsMint a new key with the right scope — scopes cannot be widened later
402A plan limit or the message-credit gateRead error.code and details; see How message credits work
404Usually the /api prefix, or a resource in another accountDrop the prefix; confirm the id belongs to your account
422Validation failedRead errors for the per-field reasons
429Rate limitedBack off and honour retry_after

Which host is which

Do not point integration code at the dashboard host. If a request returns HTML instead of JSON, that is what happened.

If your own application is built on Next.js, note that its /api/* routes belong to your app. They are not Agentency's API and they will not proxy to it.

The widget is a separate case with its own credentials. It authenticates with the public widget token in data-widget-token plus the allowed-domain list — a personal access token must never be placed in browser JavaScript, where anyone can read it. See Embed the website widget.

Limits and plan notes

Every route is rate-limited, and the limits are per surface — the chat endpoints are tighter than the read endpoints, because each chat turn costs real work. Handle 429 by backing off rather than retrying immediately in a loop.

Chat sent through the API spends message credits exactly like a visitor's message would.

Requests are scoped to the account that owns the token. A token cannot switch accounts the way you can in the dashboard: it always acts on its owner's workspace.

Ids are per account. A 404 on an id that exists is usually a sign the id belongs to a different workspace.

Common problems

Everything 404s.

Check for /api in the path first. It is the cause in most reports.

I got HTML back, not JSON.

You called the dashboard host. Use the API host from data-api-base-url or the ingest reference.

401 on a key that worked yesterday.

The key was revoked, or it reached its expiry. Keys carry an absolute expiry chosen at creation. Mint a replacement — see Rotate or revoke a key.

403 with insufficient_scope.

The route needs a scope your key does not hold. The details.required_any_of array lists which scopes would have been accepted. Scopes are fixed at creation, so create a new key. See Choose token scopes.

Requests work from my laptop and fail from my server.

Almost always the header: confirm the server is actually sending Authorization, and that the secret was not truncated on its way into your environment configuration.

Can I use my browser session token instead?

No. Dashboard sessions are for the browser and are not a supported server credential. Use a personal access token.

Common questions

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.