---
title: "List or search memories"
method: GET
path: "/v2/workspaces/{id}/memories"
tags: ["Memories"]
---

# List or search memories

`GET /v2/workspaces/{id}/memories`

## Request

- Base URL: `https://api.infolang.ai`
- URL: `https://api.infolang.ai/v2/workspaces/{id}/memories`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer
  - HTTP bearer

Without `q`: lists memories (optionally namespace-filtered). With `q`: semantic search via Kairos recall (top 20), results carry a `score`. Class A — all three lanes.

NAMESPACE SCOPING: `ns` is checked against the credential's `scoped_namespaces` after the credential is authenticated and authorized, so an out-of-scope `ns` is a 403 (never a 401). A credential restricted to exactly ONE namespace and omitting `ns` has that namespace injected; one restricted to two or more must name one.

FILTERING IS SERVER-SIDE AND CHEAPER. `tag`, `source`, `since` and `until` are applied by the engine BEFORE it hydrates any memory text, so a filtered page transfers (and meters) only the rows that matched. Filtering the returned array instead bills you for the whole namespace on every call — prefer these parameters in every case.

PAGINATION: feed `nextCursor` back as `cursor`. Filters apply BEFORE pagination, so a cursor is only meaningful when replayed with the SAME filters; change a filter and start again with no cursor. `nextCursor` is absent on the last page.

The filter and cursor parameters apply to the LIST path only. Combining any of them with `q` is a 422, not a silently ignored filter — search ranks by relevance and cannot filter on them. Drop `q` to filter, or drop the filters to search.

Requires the `memories:read` scope. Accepts all three lanes: a session JWT (bounded by the caller's role on this workspace) or an `il_*` machine credential whose own scope set, workspace set and validity window cover it — both ceilings apply and neither can raise the other, so a credential carrying `memories:read` is still refused where the role does not permit it.

A credential with no scope record resolves to `LEGACY_DEFAULT`, which INCLUDES `memories:read` — every key minted before scoping keeps working here.

## Path parameters

- `id` string, required

## Query parameters

- `ns` string
- `q` string
- `limit` number
- `cursor` string: Opaque token from the previous page's `nextCursor`.
- `tag` string: Keep memories whose tag set contains this exact value.
- `source` string: Exact match against the memory's `source`.
- `since` integer, nullable: Inclusive lower bound on `timestamp`, epoch MILLIseconds.
- `until` integer, nullable: Inclusive upper bound on `timestamp`, epoch MILLIseconds.

## Response `200`

Memories

- object
  - `memories` object[], required
    - `id` string, required
    - `text` string, required
    - `source` string, nullable
    - `tags` string[]
    - `namespace` string, required
    - `timestamp` string
    - `score` number
  - `nextCursor` string

## Other responses

- `401`: Missing/invalid credential
- `403`: The credential holds no grant on this workspace. Or `lane_not_supported` — the credential is well-formed but this route does not accept its lane
- `422`: Invalid limit, since or until
- `502`: Upstream Kairos failure
- `503`: not_ready — Kairos ML backend still warming up

---

[API](https://skmtc.dev/infolang/apis/infolang-api.md) · [All operations](https://skmtc.dev/infolang/apis/infolang-api/llms.txt) · [OpenAPI document](https://skmtc.dev/infolang/apis/infolang-api/revisions/d04bf6de72c8?raw)
