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

Where do I find my API base URL?

From the endpoint printed on the Knowledge Ingest API card at Settings → Developer, or from the data-api-base-url attribute in your widget embed snippet.

Why does everything return 404?

Check for an /api prefix in the path first — it is the cause in most reports. Some routes carry their own /v1 segment, but there is never an /api wrapper.

I got HTML back instead of JSON.

You called the dashboard host, which serves the web app. Point your client at the API host instead.

Which error code should my client branch on?

The nested error.code in the response body, not the message text, which is localised. 401 is auth, 403 insufficient_scope is a scope gap, 402 is a plan or credit gate, 429 is rate limiting.

Does an API chat message spend a message credit?

Yes. A chat turn sent through the API is charged exactly like a visitor's message on the widget or hosted page.

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.

API host — no /api prefix | Agentency Help