Lenses
Saved filter presets for the log/event explorer.
Lenses are named, saved filter presets (e.g. “Checkout errors”) scoped to a project. Mounted twice — at the plain paths below, and org/project-scoped at /api/orgs/:orgSlug/projects/:projectSlug/lenses. Both mounts run the same handler, but only the org-scoped mount resolves the project from the URL; on the plain path, project scope comes from the API key. A session cookie used on the plain path leaves the project unresolved (reads/writes effectively empty-project), so use either the plain path with an API key, or the org-scoped path with a session.
Auth: session cookie or API key (requireSession) — see Authentication
GET /api/lenses
List saved lenses for the project, ordered by sort_order then created_at.
Response 200
{
"lenses": [
{
"id": "01hxyz...",
"project_id": "proj_01abc",
"name": "Checkout errors",
"filters": "{\"level\":\"error\",\"service\":\"checkout-api\"}",
"color": "accent",
"sort_order": 0,
"created_at": 1720392000000,
"updated_at": 1720392000000
}
]
}
filters is stored and returned as an opaque string (typically JSON-encoded filter state produced by the dashboard) — it is not parsed or validated server-side.
POST /api/lenses
Create a lens. It’s appended to the end (sort_order = current max + 1).
Request body
| field | type | required | description |
|---|---|---|---|
| name | string | yes | Lens name |
| filters | string | yes | Opaque filter payload, stored as-is |
| color | string | no | Defaults to "accent" |
Response 201
{ "id": "01hxyz..." }
Note: the response is just the new ID — it does not echo back the full lens object.
Errors: 400 — { "error": "name and filters are required" }
PATCH /api/lenses/:id
Update one or more fields of a lens.
Request body
| field | type | required | description |
|---|---|---|---|
| name | string | no | |
| filters | string | no | |
| color | string | no | |
| sort_order | number | no |
Response 200
{ "ok": true }
Errors: 404 — { "error": "Not found" } if the lens doesn’t exist, or if the body contains none of the four updatable fields (an empty/all-omitted body always 404s, even for an existing lens, since there’s nothing to UPDATE).
DELETE /api/lenses/:id
Delete a lens.
Response 200
{ "ok": true }
Errors: 404 — { "error": "Not found" } if the lens doesn’t exist
Common responses (401; 402 and 429 don’t apply to these endpoints) — see Authentication.