New: Learny Brain for Sales & Support — an AI agent for your website.
Learny Brain

API

Automate Learny Brain from your own code. Create a workspace-scoped bearer token and call the API to list brains and trigger a fresh crawl of indexed URLs.

Get an API key

  1. As a workspace admin, open Settings in the left sidebar.
  2. Scroll to the API Keys panel at the bottom and click Manage API keys (or go to /settings/api-keys).
  3. Optionally give the key a name (e.g. Production script) and click Generate API key.
  4. Copy the secret shown on the next screen — it starts with lba_ and is shown only once. Store it securely; it is hashed in the database and cannot be recovered.

All keys for the workspace are listed with their prefix, name, creation date, and last-used timestamp. Revoke any key at any time — it stops working immediately.

Treat keys like passwords. Use a secrets manager or environment variable, never commit them to git, and revoke and rotate if a key may have leaked.

Authentication

Pass the key as a Bearer token in the Authorization header on every request. Keys are scoped to the workspace that created them — they cannot access other workspaces.

Authorization: Bearer lba_<your-secret>

Base URL: your workspace host, e.g. https://acme.learny.co (or https://brain.learny.co — the token determines the workspace). All API paths below are relative to that host.

curl -H "Authorization: Bearer lba_xxxxxxxxxxxxxxxx" https://acme.learny.co/api/brains

A missing or invalid token returns 401 { "error": "missing bearer token" } or 401 { "error": "invalid bearer token" }.

List brains

GET /api/brains — returns every brain in your workspace with its identifier.

GET /api/brains
Authorization: Bearer lba_...

Example response:

{
  "ok": true,
  "org": { "id": 12, "subdomain": "acme", "name": "Acme Inc" },
  "brains": [
    {
      "id": 7,
      "public_id": "3ec4c2a8-5f1e-4b5a-9b1a-0f2a5a6b7c8d",
      "name": "Company Brain",
      "slug": "company-brain",
      "is_company_brain": true,
      "access": "org"
    }
  ]
}

Use public_id (the UUID you also see in /brains/<public_id>/chat) as the brain identifier for other endpoints. id and slug are also returned for convenience.

Recrawl URLs for a brain

POST /api/brains/:brainPublicId/recrawl — re-scrapes and re-indexes every enabled context source (URLs and sitemaps) attached to that brain. This is the same job that runs on “Re-crawl all now” in the UI and on a nightly schedule, but triggered on demand. Crawls can take a while, so the endpoint is asynchronous: it responds immediately with 202 and a statusUrl you poll for completion. When the crawl finishes, every active workspace admin is emailed a summary (sources, pages indexed, per-URL status).

POST /api/brains/3ec4c2a8-5f1e-4b5a-9b1a-0f2a5a6b7c8d/recrawl
Authorization: Bearer lba_...

Example response (202):

{
  "ok": true,
  "message": "Crawling has started. Poll statusUrl for completion.",
  "brain": { "id": 7, "public_id": "3ec4c2a8-...", "name": "Company Brain" },
  "job": {
    "id": "9f3a...",
    "status": "running",
    "statusUrl": "/api/brains/3ec4c2a8-.../recrawl/jobs/9f3a...",
    "startedAt": "2026-09-18T10:00:00.000Z"
  }
}
  • 404 { "error": "brain not found" } if the UUID does not belong to your workspace.
  • 503 { "error": "crawling is not enabled for this workspace" } if URL scraping isn't configured.
  • 500 { "error": "failed to trigger recrawl" } if the job can't start.

Check a recrawl's status

GET /api/brains/:brainPublicId/recrawl/jobs/:jobId — poll the statusUrl from the 202 response. status is running, done (with result totals and a per-URL sources breakdown), or error.

GET /api/brains/3ec4c2a8-5f1e-4b5a-9b1a-0f2a5a6b7c8d/recrawl/jobs/9f3a...
Authorization: Bearer [REDACTED]

Example response (finished):

{
  "ok": true,
  "job": {
    "id": "9f3a...",
    "status": "done",
    "startedAt": "2026-09-18T10:00:00.000Z",
    "finishedAt": "2026-09-18T10:04:12.000Z",
    "result": { "sources": 3, "docs": 12, "skipped": 0 },
    "sources": [
      { "url": "https://example.com/docs", "status": "ok", "docCount": 3, "lastScrapedAt": "2026-09-18T10:01:00.000Z", "lastError": null }
    ],
    "error": null
  }
}

An unknown job ID — or one from another workspace — returns 404 { "error": "job not found" }.

Examples

curl -X POST \
  -H "Authorization: Bearer lba_xxxxxxxxxxxxxxxx" \
  https://acme.learny.co/api/brains/3ec4c2a8-5f1e-4b5a-9b1a-0f2a5a6b7c8d/recrawl
// Node.js (Node 18+)
const res = await fetch('https://acme.learny.co/api/brains/3ec4c2a8-.../recrawl', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + process.env.LEARNY_API_KEY }
});
const started = await res.json();
console.log(started.job.statusUrl); // poll this until job.status === 'done'
let job;
do {
  await new Promise((r) => setTimeout(r, 5000));
  const poll = await fetch('https://acme.learny.co' + started.job.statusUrl, {
    headers: { 'Authorization': 'Bearer ' + process.env.LEARNY_API_KEY }
  });
  job = (await poll.json()).job;
} while (job.status === 'running');
console.log(job.result); // { sources: 3, docs: 12 }

Rate limits & errors

The API shares the global rate limiter (400 requests per 15 minutes per IP) and the per-brain crawl limits. Exceeding it returns 429. All endpoints return JSON; non-2xx responses include an error key.

What’s next: listing brains and recrawling URLs are the first endpoints. We’ll expand the API over time; this page will stay up to date as new capabilities land.