---
title: "Create a knowledge-base page"
method: POST
path: "/v1/default/banks/{bank_id}/knowledge-base/pages"
tags: ["Knowledge Base"]
---

# Create a knowledge-base page

`POST /v1/default/banks/{bank_id}/knowledge-base/pages`

## Request

- Base URL: `https://hindsight.vectorize.io` (the document declares no server; this is the origin it was published from)
- URL: `https://hindsight.vectorize.io/v1/default/banks/{bank_id}/knowledge-base/pages`
- Auth: none declared
- TypeScript: <https://skmtc.dev/vectorize/apis/hindsight-http-api/docs/v1/default/banks/:bank_id/knowledge-base/pages/post.ts> (a function with typed inputs; its response is checked against the schema)

Create a page (a mental model + tree node). Content is generated asynchronously; use the returned operation_id to track completion.

## Path parameters

- `bank_id` string, required

## Headers

- `authorization` string, nullable

## Request body

- CreatePageRequest: Create a page (a mental model + tree node) under an optional parent folder.
  - `name` string, required
  - `source_query` string, required
  - `parent_id` string, nullable
  - `tags` string[], nullable: Tags that SCOPE which memories this page is built from — not labels. Every tag here, including a `type:<x>` tag used to set the page's rendered type, is part of the filter. By default a tagged page matches with `all_strict`: a memory must carry EVERY one of these tags, and untagged memories are excluded entirely. Tags invented for the page (a topic, a document type) therefore match nothing unless your memories were retained with those exact tags, and the page generates as 'I don't have information about this'. Omit this field to build the page from the whole bank, or set `trigger.tags_match` to 'all' to require the tags while still including untagged memories.
  - `max_tokens` integer, nullable
  - `trigger` MentalModelTriggerInput: Trigger settings for a mental model. A refresh is not an ad-hoc reflect with different arguments: it synthesizes a whole document, so it wants its own retrieval and iteration settings. This trigger is therefore the only source for them — a bank's ``reflect_default_options`` deliberately does not reach a refresh. The per-bank default for these fields is ``knowledge_page_default_trigger``, which is merged over this same shape when a page is created.
    - `budget` 'low' | 'mid' | 'high': Budget levels for recall/reflect operations.
    - `mode` 'full' | 'delta': Refresh mode. 'full' (default) regenerates the mental model content from scratch on each refresh. 'delta' performs surgical edits against the existing content: unchanged sections are preserved byte-for-byte, stale content is removed, new content is added. If the mental model has no existing content, or if the source_query has changed since the last refresh, delta mode falls back to a full regeneration automatically.
    - `refresh_after_consolidation` boolean: If true, refresh this mental model after observations consolidation (real-time mode)
    - `refresh_cron` string, nullable: Cron expression (UTC, standard 5-field syntax, e.g. '0 3 * * *' for daily at 03:00 UTC) for refreshing this mental model on a fixed schedule. Mutually exclusive with refresh_after_consolidation — a model refreshes either after consolidation or on a cron schedule, not both. A scheduled refresh only runs when the model is stale (new memories in its scope since the last refresh); if nothing changed, the tick is skipped to avoid a wasted LLM call. null = no schedule.
    - `full_refresh_cron` string, nullable: Cron expression (UTC, standard 5-field syntax, e.g. '0 3 * * 0' for Sundays at 03:00 UTC) for a scheduled full refresh: on this schedule the model is refreshed in 'full' mode whatever its `mode` says, regenerating the content from scratch to clear the drift many delta edits accumulate. Independent of `refresh_cron` and `refresh_after_consolidation` — a delta model can refresh after consolidation and still get a weekly full refresh — and it does not change `mode`. A tick is skipped when no refresh has run since the last full one (there is nothing to correct). Like `refresh_cron`, it honours `min_refresh_interval_seconds` and pauses while the last refresh failed. null = no schedule.
    - `min_refresh_interval_seconds` integer, nullable: Minimum seconds between two automatic refreshes of this mental model. A triggered refresh that arrives sooner is not dropped: it is queued and parked until the window expires, and every further trigger in the meantime folds into that one queued refresh, so a burst of retains costs one refresh instead of one per retain. Applies to every automatic trigger: refresh_after_consolidation, refresh_cron and full_refresh_cron. Explicit refreshes (API, MCP, control plane) ignore it and run immediately. 0 disables the floor for this model; null falls back to the bank/global mental_model_min_refresh_interval_seconds setting (itself 0 by default, i.e. no floor).
    - `fact_types` string[], nullable: Filter which fact types are retrieved during reflect. None means all types (world, experience, observation).
    - `exclude_mental_models` boolean: If true, exclude all mental models from the reflect loop (skip search_mental_models tool).
    - `exclude_mental_model_ids` string[], nullable: Exclude specific mental models by ID from the reflect loop.
    - `tags_match` 'any' | 'all' | 'any_strict' | 'all_strict' | 'exact', nullable: Override how the model's tags filter memories during refresh. If not set, defaults to 'all_strict' when the model has tags (security isolation) or 'any' when the model has no tags. Under 'all_strict' a memory must carry EVERY one of the model's tags and untagged memories are excluded, which is why a model tagged with labels its memories do not carry refreshes to empty content. Set to 'all' to keep requiring the tags while including untagged memories, or to 'any' to include untagged memories alongside any single tag match. Staleness ignores that widening: an untagged write never marks a tagged model stale, in any mode — only a write that matches the model's tags does.
    - `tag_groups` union[], nullable: Compound boolean tag expressions to use during refresh instead of the model's own tags. When set, these tag groups are passed to reflect and the model's flat tags are NOT used for filtering. Supports nested and/or/not expressions for complex tag-based scoping.
      - union
        - TagGroupLeaf: A leaf tag filter: matches memories by tag list and match mode.
          - `tags` string[], required
          - `match` 'any' | 'all' | 'any_strict' | 'all_strict' | 'exact'
          - `resolve` 'exact' | 'fuzzy'
        - TagGroupAndInput: Compound AND group: all child filters must match.
          - `and` union[], required
            - union
              - …
        - TagGroupOrInput: Compound OR group: at least one child filter must match.
          - `or` union[], required
            - union
              - …
        - TagGroupNotInput: Compound NOT group: child filter must NOT match.
          - `not` union, required
            - TagGroupLeaf: A leaf tag filter: matches memories by tag list and match mode.
              - …
            - TagGroupAndInput: Compound AND group: all child filters must match.
              - …
            - TagGroupOrInput: Compound OR group: at least one child filter must match.
              - …
            - TagGroupNotInput (recursive)
    - `include_chunks` boolean, nullable: Override whether the internal recall used during refresh returns raw chunk text. None means use the bank/global config default (recall_include_chunks).
    - `recall_max_tokens` integer, nullable: Override the token budget for facts returned by the internal recall during refresh. None means use the bank/global config default (recall_max_tokens).
    - `recall_chunks_max_tokens` integer, nullable: Override the token budget for raw chunks returned by the internal recall during refresh. None means use the bank/global config default (recall_chunks_max_tokens).
    - `reflect_search_observations_max_tokens` integer, nullable: Override the token budget for the refresh's search_observations calls. Observation evidence is often the largest contributor to the reflect context; lowering it trades the lowest-ranked observations for a smaller LLM context. null means the shipped 5000.
    - `reflect_search_observations_include_entities` boolean, nullable: Override whether search_observations attaches resolved entity names to each observation. Entities can be more than half the serialized tool payload; turning them off keeps the same observations and ranking with a much smaller context. null means enabled.
    - `response_schema` object, nullable: Optional JSON Schema for structured output. When set, each refresh runs the same structured-output extraction as reflect's response_schema and stores the parsed result under reflect_response.structured_output alongside the markdown content.
    - `keep_trace` boolean: If true, every refresh of this mental model records how it reached its result under reflect_response.trace: the mode it ran in and why, the resolved scope and time window, how many facts retrieval returned versus how many the agent used, the tool and LLM calls, and any delta operations. Only the latest refresh's trace is kept. This is the only way to diagnose a cron- or consolidation-driven refresh after the fact, since no human sees those run. Tool outputs are reduced to result counts to keep the stored trace bounded; use LLM request tracing for raw prompts and responses.

## Response `201`

Successful Response

- CreateKnowledgePageResponse: Result of creating a page: the node id, its mental model, and the refresh op.
  - `page_id` string, required
  - `mental_model_id` string, required
  - `operation_id` string, nullable

## Other responses

- `422`: Validation Error

## Changes

- **2026-11-07** `45e711cd0897`: 2 warning, 1 info
  - the `max_tokens/anyOf[subschema #1]/` request property's max was set to `8192.00`
  - the `max_tokens/anyOf[subschema #1]/` request property's min was set to `256.00`
  - added the new optional request property `trigger/anyOf[subschema #1: MentalModelTrigger]/full_refresh_cron`
- **2026-10-04** `4fda98b75f63`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/vectorize/apis/hindsight-http-api/changes/v1/default/banks/:bank_id/knowledge-base/pages/post.md)

---

[API](https://skmtc.dev/vectorize/apis/hindsight-http-api.md) - [All operations](https://skmtc.dev/vectorize/apis/hindsight-http-api/llms.txt) - [OpenAPI document](https://skmtc.dev/vectorize/apis/hindsight-http-api/revisions/45e711cd0897?raw)
