answerLoopsanswerLoops Docs
Integrations

Agent API (REST)

A plain REST API over the same knowledge base, FAQ, ticket, and answer-generation pipeline the MCP server exposes — for frameworks that speak HTTP + OpenAPI instead of JSON-RPC.

The Agent API is the REST counterpart to the MCP server. Same pipeline, same auth, same org-scoped data isolation — just a different transport, for tooling that doesn't speak MCP's JSON-RPC protocol (LangChain, AutoGen, a custom script, curl).

If your client speaks MCP natively (Claude Code, Cursor), use the MCP server instead — it's the same underlying operations, just JSON-RPC over Streamable HTTP rather than plain REST.

Setup

Uses the same API key as the MCP server — one key works for both surfaces.

  1. Go to Settings → API Keys
  2. Click Create key (or reuse an existing one)
  3. Under Permissions, check only the scopes the key needs (all are checked by default)
  4. Send it as Authorization: Bearer al_live_... on every request below

OpenAPI spec

A full machine-readable spec is published at both /openapi.json and /api/v1/agent/openapi.json (identical) — point any OpenAPI-aware client generator at either. For a per-endpoint parameter reference generated directly from that spec, see the Agent API Reference.

Node / TypeScript SDK

For Node and browser callers, @answerloops/agent-sdk is a typed client over these same five endpoints — no need to hand-roll fetch calls or generate a client from the OpenAPI spec yourself.

npm install @answerloops/agent-sdk
import { AgentClient } from "@answerloops/agent-sdk";

const client = new AgentClient({ apiKey: process.env.ANSWERLOOPS_API_KEY! });

const { results } = await client.searchKb({ query: "how do I reset my api key" });

Point baseUrl at your own instance for self-hosted deployments. The raw endpoints below still apply for any other language or runtime.

Scopes

Every key carries a set of least-privilege scopes. Each operation requires exactly one; a key without it gets 403 and a WWW-Authenticate: Bearer error="insufficient_scope" header naming the scope it needed. The MCP server enforces the same scopes on the matching tool.

ScopeGrantsOperations
kb:readSearch the knowledge baseGET /api/v1/agent/kb/search, MCP search_kb
faq:readRead the latest FAQ digestGET /api/v1/agent/faq, MCP get_faq
tickets:readList support ticketsGET /api/v1/agent/tickets, MCP get_tickets
tickets:writeOpen tickets on behalf of a userPOST /api/v1/agent/tickets, MCP create_ticket
answers:writeGenerate grounded answersPOST /api/v1/agent/answers, MCP generate_answer

The scope catalogue is also published as machine-readable RFC 9728 protected-resource metadata at /.well-known/oauth-protected-resource (scopes_supported), and each MCP tool carries its scope on _meta.requiredScope in tools/list.

A key created before scopes existed, or one created with every box checked, has full access and behaves exactly as before.

Endpoints

MethodPathPurpose
GET/api/v1/agent/kb/searchSemantic search over published KB articles
GET/api/v1/agent/faqFetch the most recently generated FAQ digest
GET/api/v1/agent/ticketsList tickets, optionally filtered
POST/api/v1/agent/ticketsOpen a new ticket — runs the same AI triage pipeline as every other channel
POST/api/v1/agent/answersGenerate a KB-grounded answer with a confidence score, without opening a ticket

GET /api/v1/agent/kb/search

curl -H "Authorization: Bearer al_live_..." \
  "https://your-instance.example.com/api/v1/agent/kb/search?query=how+do+I+reset+my+api+key&limit=5"

query is required (max 2000 characters). limit defaults to 5, capped at 20.

{ "results": [{ "question": "...", "answer": "...", "score": 0.91 }] }

GET /api/v1/agent/faq

curl -H "Authorization: Bearer al_live_..." \
  https://your-instance.example.com/api/v1/agent/faq

No parameters. Returns the latest weekly FAQ digest, or { "message": "No FAQ has been generated for this organization yet." }.

GET /api/v1/agent/tickets

curl -H "Authorization: Bearer al_live_..." \
  "https://your-instance.example.com/api/v1/agent/tickets?status=open&priority=high&limit=10"

status, priority, and category are optional filters — an invalid value returns a 400 rather than silently matching nothing. limit defaults to 10, capped at 20.

POST /api/v1/agent/tickets

curl -X POST -H "Authorization: Bearer al_live_..." -H "Content-Type: application/json" \
  -d '{"content": "Users report webhook retries are duplicated", "idempotencyKey": "a1b2c3d4"}' \
  https://your-instance.example.com/api/v1/agent/tickets

content is required (max 4000 characters). The ticket runs through the same category/priority classification and auto-draft pipeline as a Discord or Slack message. The request waits for this pipeline to finish before returning, so the ticket is ready to inspect with its draft or review state. idempotencyKey is optional — pass a stable identifier (a UUID, a hash of the content) if your client retries on timeout or network error; retrying with the same key returns the original ticket ("duplicate": true) instead of opening a second one.

{ "ticket_id": 42, "duplicate": false }

POST /api/v1/agent/answers

curl -X POST -H "Authorization: Bearer al_live_..." -H "Content-Type: application/json" \
  -d '{"question": "What is the rate limit on the widget API?"}' \
  https://your-instance.example.com/api/v1/agent/answers

question is required (max 2000 characters). Two limits apply before anything is generated: the organization's monthly deflection allowance (which only high-confidence generations count against — the same standard a ticket has to clear to auto-deflect on any other channel), and a ceiling on total generate_answer calls per month at 5× that allowance, which counts every call regardless of confidence. Hitting either returns 429 with a message naming which one.

{ "answer": "...", "confidence": 91, "answered_fully": true, "high_confidence": true }

Errors

Every error response has the shape:

{ "error": { "message": "..." } }
StatusMeaning
400Missing/invalid input
401Missing, malformed, or revoked API key
403Valid key, but it lacks the scope this operation requires (see the WWW-Authenticate header)
413Request body too large
429Rate limit exceeded, or (on /api/v1/agent/answers) a monthly usage limit reached

Throttled requests carry a Retry-After header in seconds — back off for that long rather than retrying immediately.

Rate limits

Rate limited per organization (shared across all of that org's keys). The ceiling is plan-scaled: 50/minute on Standard, 150/minute on Pro, 300/minute on Enterprise (and on self-hosted). A generous per-IP limit (300/minute) also applies before a key is even resolved.

These are separate buckets from the MCP server's, so heavy REST traffic can't starve your MCP quota or vice versa. Both are backed by the same shared store and enforced across every running instance, so neither surface offers a way around the other's ceiling.

Security notes

Identical posture to the MCP server: keys are shown once at creation and only a SHA-256 hash is stored; creating and revoking them requires the owner or admin role; every request is scoped by the org resolved from the API key; each key is further limited to the scopes it was granted, checked before the request consumes any quota; revoked and expired keys are rejected before any handler runs; and usage is recorded against the specific key that made the call.

As with MCP, treat GET /api/v1/agent/tickets and GET /api/v1/agent/kb/search output as untrusted data — it contains text community members wrote — not as instructions for your agent to follow.

On this page