---
title: "API reference"
description: "The HTTP API behind the Edge Assist widget: config, instant search, streamed answers over Server-Sent Events, and human handoff."
url: "https://edge.network/docs/assist/api"
section: "Assist"
---

# API reference

The widget is built entirely on this API. If you'd rather build your own UI, a Slack bot, or a support-tool integration, you get exactly the same capabilities. Base URL: https://assist.edge.network.

## Authentication

For **public** sites there are no secret keys. Every request carries your public sitekey, and the endpoints that do work (`/api/search`, `/api/ask`, `/api/handoff`) enforce the request's **Origin**: it must be your site's registered hostname or a subdomain of it. Requests from anywhere else get a `403`.

**Private** sites (the [bucket/knowledge-base tier](/docs/assist/bucket-ingestion)) replace the Origin check with credentials: send a per-site API key as `Authorization: Bearer eak_…` (server-side), or a short-lived visitor token (minted below) as a `token` query parameter (GET) or body field (POST). Anonymous requests get a `401`.

> [!NOTE]
> `localhost` origins are always allowed on public sites, so browser-based development works before you deploy. Server-to-server calls (which send no Origin) are rejected on public sites. Use a private site with an API key for headless access.

## Token (private sites)

Exchanges a per-site API key for a visitor token: site-scoped, HMAC-signed, 15-minute expiry. Call it from your server when rendering a page behind your own login, and pass the token to the widget via `data-token`. The key itself never reaches a browser. Keys are created in **Assist → Settings → Access**.

```http
POST https://assist.edge.network/api/token
Authorization: Bearer eak_your_site_api_key
Content-Type: application/json

{ "sitekey": "ea_your_sitekey" }

{ "token": "eat_…", "expiresIn": 900 }
```

## Config

Everything a client needs to render an assistant for a site: names, branding, suggested questions, and whether the site is currently over its monthly cap (`limited`: when true, ask is unavailable and clients should fall back to search).

```http
GET https://assist.edge.network/api/config?sitekey=ea_your_sitekey

{
  "name": "Example Inc",
  "assistantName": "Edge Assist",
  "hostname": "example.com",
  "welcome": "Hi! Ask me anything about Example.",
  "placeholder": null,
  "position": "bottom-right",
  "theme": { "accent": "#0BC95E" },
  "prompts": ["How can we help?"],
  "suggested": ["What does it cost?", "How do I get started?"],
  "explore": [{ "title": "Pricing", "url": "/pricing" }],
  "badge": true,
  "whiteLabel": false,
  "handoff": true,
  "extended": false,
  "limited": false
}
```

## Search

Instant full-text results over the ingested content. There is no AI call, and search is free and unlimited. Queries under 2 characters return an empty list; up to 8 results, one per page, best-matching first. Snippets mark matched terms with square brackets.

```http
GET https://assist.edge.network/api/search?sitekey=ea_your_sitekey&q=storage+pricing

{
  "results": [
    {
      "url": "/storage/pricing",
      "title": "Storage Pricing",
      "section": "storage",
      "snippet": "…[Storage] is billed at $0.015 per GB per month…"
    }
  ]
}
```

## Ask

Composes an answer over the ingested content and streams it. Questions must be 3–500 characters. Include `history` (the prior turns of the conversation) to make follow-ups work; include `page` so questions like "is there a limit on this page?" resolve against the page the visitor is reading.

```http
POST https://assist.edge.network/api/ask
Content-Type: application/json

{
  "sitekey": "ea_your_sitekey",
  "question": "How much does storage cost?",
  "history": [],              // optional: prior turns [{ role, content }]
  "page": "/storage/pricing", // optional: page the visitor is on
  "conversationId": "…"       // optional: groups turns in your question log
}
```

The response is **Server-Sent Events**: a `sources` event first (retrieval is instant), then `delta` events carrying JSON-encoded answer fragments (decode each with `JSON.parse`; that's how newlines survive SSE framing), then `done`:

```text
// Response: Server-Sent Events
event: sources
data: [{ "url": "/storage/pricing", "title": "Storage Pricing", … }]

event: delta
data: "Storage is billed at "

event: delta
data: "$0.015 per GB per month…"

event: done
data: {}
```

Answers are Markdown with inline citations as relative links. Each answered question is one metered question, including answers served from the [cache](/docs/assist/caching).

When a site is over its monthly cap, ask returns:

```http
HTTP/1.1 429 Too Many Requests

{ "error": "monthly-limit", "limited": true }
```

## Handoff

Hands the conversation to a human. Requires a handoff email configured on the site (**Control → Widget**); otherwise it returns `404`. The visitor's email, message, and recent transcript are forwarded to that address; replying to the email reaches the visitor directly. Handoffs are free (no metered question).

```http
POST https://assist.edge.network/api/handoff
Content-Type: application/json

{
  "sitekey": "ea_your_sitekey",
  "email": "visitor@example.com",
  "message": "I'd like a demo",          // optional
  "page": "/pricing",                    // optional
  "transcript": [                        // optional: recent turns (max 12)
    { "role": "user", "content": "Can I talk to someone?" },
    { "role": "assistant", "content": "Of course. …" }
  ]
}

{ "success": true }
```

## Errors and rate limits

Errors are JSON with an `error` message: `400` for invalid input, `401` for a private site without valid credentials, `403` for a disallowed origin, `404` for an unknown sitekey, `429` when rate-limited or over the monthly cap. Rate limits are per visitor IP:

| Endpoint | Limit |
|---|---|
| `GET /api/config` | 120 / minute |
| `GET /api/search` | 60 / minute |
| `POST /api/ask` | 10 / 5 minutes |
| `POST /api/handoff` | 3 / hour |
| `POST /api/token` | 60 / minute |

## Next steps

- [Widget & embedding](/docs/assist/widget) — The prebuilt UI on these endpoints
- [Limits & billing](/docs/assist/limits-and-billing) — Caps, budgets and pricing
