---
title: "Create a memory rule"
method: POST
path: "/v1/projects/{project_id}/memory-rules"
tags: ["Memory Rules"]
---

# Create a memory rule

`POST /v1/projects/{project_id}/memory-rules`

## Request

- Base URL: `https://api.naturali.ai`
- URL: `https://api.naturali.ai/v1/projects/{project_id}/memory-rules`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.naturali.ai/authorize`, token URL `https://api.naturali.ai/token`, scopes: `mcp:access`)

Creates an ingestion rule on a memory store. With neither `agent_id` nor `tool_id` the built-in extractor runs, configurable through `prompt`, `ai_provider_id` and `model`.

## Request body

- object
  - `memory_store_id` string, required: The destination store, and the rule's owning scope
  - `on` 'generations.completed' | 'conversation_messages.generated', required: The event a firing reads. `generations.completed` fires once per completed turn whatever the transport, and is the only event the built-in extractor may bind to. `conversation_messages.generated` fires per persisted assistant reply and is conversation-backed, so it is for custom handlers.
  - `source_agent_ids` string[], nullable: Agents whose turns this rule reads. Omit or send `null` for every agent in the store's project.
  - `agent_id` string, nullable: Handler agent (mutually exclusive with tool_id)
  - `tool_id` string, nullable: Handler tool (mutually exclusive with agent_id)
  - `action` string, nullable: Operation id, for a tool handler
  - `preset_parameters` object, nullable: Merged into a tool handler's input before invocation. The turn's own fields are reserved and win.
  - `prompt` string, nullable: Replaces the built-in extractor's task instructions. The JSON response contract and the transcript are always appended. Not valid with a handler.
  - `ai_provider_id` string, nullable: Provider override for the built-in extractor's completion. Not valid with a handler.
  - `model` string, nullable: Model override for the built-in extractor's completion. Not valid with a handler.
  - `enabled` boolean: A disabled rule is kept and never fires

## Response `201`

Memory rule created

- MemoryRule
  - `id` string
  - `memory_store_id` string
  - `project_id` string
  - `on` 'generations.completed' | 'conversation_messages.generated': The event a firing reads. `generations.completed` fires once per completed turn whatever the transport, and is the only event the built-in extractor may bind to. `conversation_messages.generated` fires per persisted assistant reply and is conversation-backed, so it is for custom handlers.
  - `source_agent_ids` string[], nullable
  - `agent_id` string, nullable
  - `tool_id` string, nullable
  - `action` string, nullable
  - `preset_parameters` object, nullable
  - `prompt` string, nullable
  - `ai_provider_id` string, nullable
  - `model` string, nullable
  - `enabled` boolean
  - `created_at` string, date-time
  - `updated_at` string, date-time

## Other responses

- `400`: Validation failed (e.g. agent_id and tool_id both set, or an extractor override combined with a handler)
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Memory store not found
- `500`: Internal server error

---

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