> ## Documentation Index
> Fetch the complete documentation index at: https://docs.memoryo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /v1/memories/add

> Queue conversation ingestion for memory extraction.

## Endpoint

```http theme={null}
POST /v1/memories/add
```

## Authentication

```http theme={null}
Authorization: ApiKey mem_live_xxx
Content-Type: application/json
```

## Simple mode: no source block required

<Tip>
  For solo builders, MVPs, small teams, and single-agent products, omit `source`. MemoryOS automatically creates internal event IDs, timestamps, and default provenance.
</Tip>

## Request body

```json theme={null}
{
  "external_user_id": "customer_123",
  "agent_id": "support-bot",
  "messages": [
    {
      "role": "user",
      "content": "Please remember that I prefer weekly summaries."
    }
  ],
  "metadata": {
    "source": "chat"
  }
}
```

### Fields

| Field              | Type                    | Required | Notes                                                |
| ------------------ | ----------------------- | -------- | ---------------------------------------------------- |
| `external_user_id` | `string`                | Yes      | End-user identifier inside your tenant               |
| `agent_id`         | `string \| null`        | No       | Optional agent identifier                            |
| `messages`         | `ConversationMessage[]` | Yes      | At least one message                                 |
| `metadata`         | `object`                | No       | Arbitrary JSON metadata                              |
| `source`           | `MemorySource \| null`  | No       | Provenance source block for multi-service governance |

### ConversationMessage

| Field     | Type                                | Required |
| --------- | ----------------------------------- | -------- |
| `role`    | `"user" \| "assistant" \| "system"` | Yes      |
| `content` | `string`                            | Yes      |

## Multi-service mode: add provenance

<Warning>
  Use `source` when multiple services can write memories for the same user. This is for Billing, Support, CRM, Product, or other backend services that may disagree and need source-of-truth routing.
</Warning>

```json theme={null}
{
  "external_user_id": "customer_123",
  "messages": [
    {
      "role": "user",
      "content": "What plan am I currently using?"
    },
    {
      "role": "assistant",
      "content": "Your current subscription plan is Growth."
    }
  ],
  "source": {
    "service": "billing-service",
    "event_id": "billing-plan-2026-06-30-001",
    "observed_at": "2026-06-30T10:00:00Z",
    "scope": {
      "workspace_id": "ws_123"
    },
    "evidence": [
      {
        "source_type": "subscription_record",
        "reference": "billing/subscriptions/ws_123"
      }
    ]
  }
}
```

For testing, you may start with one tenant API key and a `source.service` value. For production multi-service traffic, register service writers from the Tenant Dashboard and bind dedicated API keys so authority rules can be applied consistently.

## Response: queued

```json theme={null}
{
  "job_id": "72a20629-a76d-4a18-ab36-1c2778ba21d0",
  "status": "queued",
  "blocked_reason": null,
  "nothing_to_extract": false,
  "retry_after_seconds": null,
  "budget_remaining_pct": 0.9134,
  "processing_eta_seconds": null,
  "processing_status": "normal",
  "request_id": "c3d4fd63-77ff-48b6-9316-6bcbadf9476b",
  "timestamp": "2026-04-05T09:23:40.077265Z"
}
```

`add()` is asynchronous. A queued response means MemoryOS accepted the request, not that a memory has already been stored.

## Check extraction job status

```http theme={null}
GET /v1/memories/jobs/{job_id}
Authorization: ApiKey mem_live_xxx
```

Example response:

```json theme={null}
{
  "data": {
    "job_id": "72a20629-a76d-4a18-ab36-1c2778ba21d0",
    "status": "completed",
    "memories_created": 0,
    "pending_candidates_buffered": 1,
    "pending_candidates_promoted": 0,
    "attempts": 2,
    "queue_name": "free-extraction",
    "error": null,
    "error_summary": null,
    "extraction_metadata": {
      "compositional_pass_attempted": false,
      "compositional_pass_used": false,
      "compositional_entities": 0,
      "compositional_relationships": 0,
      "compositional_error": null
    }
  }
}
```

### Job status fields

| Field                         | Meaning                                                   |
| ----------------------------- | --------------------------------------------------------- |
| `memories_created`            | Permanent memories created                                |
| `pending_candidates_buffered` | Weak signals buffered instead of stored                   |
| `pending_candidates_promoted` | Weak signals promoted to memory                           |
| `attempts`                    | Number of processing attempts, including provider retries |
| `extraction_metadata`         | Two-pass compositional extraction details                 |

## Working PowerShell polling example

```powershell theme={null}
$Api = $env:MEMORYOS_API_BASE_URL
if (-not $Api) { $Api = "https://api.memoryo.dev" }

$TenantKey = $env:MEMORYOS_API_KEY
if (-not $TenantKey) { throw "Set MEMORYOS_API_KEY before running this example." }

$UserId = "customer_123"

$body = @{
  external_user_id = $UserId
  messages = @(
    @{
      role = "user"
      content = "Maybe I prefer shorter replies for difficult technical topics, but I am not completely sure yet."
    },
    @{
      role = "assistant"
      content = "Got it. I will adapt if that pattern becomes clearer."
    }
  )
} | ConvertTo-Json -Depth 10

$add = Invoke-RestMethod `
  -Method Post `
  -Uri "$Api/v1/memories/add" `
  -Headers @{
    Authorization = "ApiKey $TenantKey"
    "Content-Type" = "application/json"
  } `
  -Body $body

$JobId = $add.job_id

for ($i = 1; $i -le 60; $i++) {
  Start-Sleep -Seconds 3

  $job = Invoke-RestMethod `
    -Method Get `
    -Uri "$Api/v1/memories/jobs/$JobId" `
    -Headers @{ Authorization = "ApiKey $TenantKey" }

  Write-Host "Attempt $i -> status=$($job.data.status), memories=$($job.data.memories_created), buffered=$($job.data.pending_candidates_buffered)"

  if ($job.data.status -in @("completed", "processed", "failed", "dead")) {
    $job.data | ConvertTo-Json -Depth 10
    break
  }
}
```

## Response: blocked by the quality gate

```json theme={null}
{
  "job_id": null,
  "status": "L2",
  "blocked_reason": "low_quality",
  "retry_after_seconds": null,
  "budget_remaining_pct": 0.9134,
  "request_id": "11111111-2222-3333-4444-555555555555",
  "timestamp": "2026-04-17T09:30:00Z"
}
```

Possible blocked `status` values: `L1`, `L2`, `L3`, `L4`, and `blocked`.

## Nothing to extract

Some conversations pass the quality gate but contain no durable memory. This is normal.

Examples:

* greetings
* acknowledgements
* one-session debugging instructions
* temporary UI instructions
* off-topic questions

## Idempotency-Key

Use `Idempotency-Key` when your application may retry the same write request.

```http theme={null}
Idempotency-Key: 8b7f95f1-a98c-4d43-b321-889e881d29b8
```

MemoryOS replays the same queued response for duplicate requests instead of creating a second job.

## Related pages

* [Extraction Quality Loop](/concepts/extraction-quality)
* [Quality Gate](/concepts/quality-gate)
* [Memory Provenance](/concepts/provenance)
