# The LightHouse API

> LightHouse's HTTP API: your tenant's host, authentication, conventions, and the generated reference.

The LightHouse API is the HTTP interface to everything LightHouse shows: agents, runs, usage and cost, evidence, knowledge bases, approvals, limits, access and keys. The portal uses it too: what you see in LightHouse is what the API returns.

## The tenant host and base path

Every request goes to your tenant’s own host:

```text
https://<tenant id>.atlanticagenticlabs.com/api/v1/...
```

The tenant comes from the hostname and nothing else. Every request is authenticated (see [Authentication](/api/authentication/)) and every query runs under your tenant’s row-level security scope.

## A first request

**curl**

```bash
curl -s "https://$AAL_TENANT.atlanticagenticlabs.com/api/v1/runs?limit=5" \
  -H "Authorization: Bearer $AAL_KEY" \
  -H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
  -H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET"
```

**Python**

```python
import os

import httpx

client = httpx.Client(
    base_url=f"https://{os.environ['AAL_TENANT']}.atlanticagenticlabs.com/api/v1",
    headers={
        "Authorization": f"Bearer {os.environ['AAL_KEY']}",
        "CF-Access-Client-Id": os.environ["CF_ACCESS_CLIENT_ID"],
        "CF-Access-Client-Secret": os.environ["CF_ACCESS_CLIENT_SECRET"],
    },
)
r = client.get("/runs", params={"limit": 5})
r.raise_for_status()
for run in r.json()["runs"]:
    print(run["started_at"], f"{run['pack']}:{run['card']}", run["status"])
```

**TypeScript**

```ts
const base = `https://${process.env.AAL_TENANT}.atlanticagenticlabs.com/api/v1`;
const headers = {
  Authorization: `Bearer ${process.env.AAL_KEY}`,
  "CF-Access-Client-Id": process.env.CF_ACCESS_CLIENT_ID!,
  "CF-Access-Client-Secret": process.env.CF_ACCESS_CLIENT_SECRET!,
};
const res = await fetch(`${base}/runs?limit=5`, { headers });
if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).error}`);
const { runs } = await res.json();
for (const run of runs) console.log(run.started_at, `${run.pack}:${run.card}`, run.status);
```

The answer is `{"runs": [...], "next": "<cursor or null>"}`. See [Pagination](/api/pagination/).

## Conventions

- **JSON** in and out. A write’s body is a JSON object.
- **Timestamps** are RFC 3339, in UTC. Query parameters such as `since` and `until` take the same.
- **Money** is in the provider’s own currency, with a `*_usd` figure beside it. Reads of money also give `*_money` figures in the caller’s display currency, set under **Settings → Preferences**.
- **Identifiers**: an agent is `<pack>:<card>`; a run is its `run_id_hash`. See [Agents](/concepts/agents/) and [Runs](/concepts/runs/).
- **Counts, never content.** Apart from the content routes, which read in place from your deployment and need `content_viewer`, no answer carries prompt, answer or document text.
- **Refusals** are `{"error": "<code>", "message": "..."}` with a fixed code, and `Cache-Control: no-store`. See [Errors](/api/errors/).
- **People-only routes**: anything that approves, decides, pays, changes a limit or changes access refuses a machine key (`403 person_required` or `role_required`). See [Authentication](/api/authentication/#what-a-machine-key-may-never-do).

## The reference

The [API reference](/api/reference/) is generated from LightHouse’s own OpenAPI document, so it cannot drift from the service. Download it: [openapi.json](/openapi.json). The same reads are available as [MCP tools](/mcp/).

Source: https://docs.atlanticagenticlabs.com/api/
