---
title: "Endpoint reference"
description: "Five endpoints under /api/v1, and what is coming. Every field below is the wire name."
canonical: https://past.dev/docs/memory-api/api-reference
last-updated: 2026-08-26
---
# Endpoint reference

> Five endpoints under /api/v1, and what is coming. Every field below is the wire name.

Product: past.dev Memory API. Source: https://past.dev/docs/memory-api/api-reference

### POST /api/v1/ingest

Push one unit of content. Each project has a sequential queue, so content applies in the order it is sent.

| Field | Description |
| --- | --- |
| `content` (string, required) | The raw text. No shape is imposed. |
| `label` (string) | Human-readable descriptor for the kind of content. Defaults to "Ingested data point". |
| `id` (string) | Stable identifier for this source. Re-sending the same id replaces the stored point and re-derives it. Omit and one is generated. |
| `timestamp` (ISO 8601) | When the content happened, not when it was sent. Backdatable. Defaults to now. Stored at microsecond precision. |
| `metadata` (object) | Arbitrary JSON stored alongside the point and never interpreted. |
| `append` (boolean) | Splice content onto the stored point (a newline joins them) instead of replacing it, for a growing log or a continuing conversation. |
| `group` (string) | Free-form grouping key, max 200 characters. |
| `audience` (array of integers) | Audience ids this point is scoped to. Omit and the point is visible to the whole project. Audiences are configured with past.dev during early access. |
| `projectId` (integer) | Names the project when the key's organization has several. Omit with a single project. |

```202accepted
{
  "projectId": 12,
  "ingestionId": "7d9f2b6a-4c1e-4f8a-9b3d-2e5c8a1f6d40",
  "sourceId": "call-8821",
  "status": "queued"
}
```

Re-sending an unchanged point returns **200** with `"unchanged": true` and the existing `ingestionId` instead of queueing anything.

### GET /api/v1/ingest/{ingestionId}

Poll until the queue has applied the content and finished its deferred maintenance. `ingestionId` is the id `POST /api/v1/ingest` returned. Pass `projectId` as a query parameter if the organization has several projects.

```200ok
{
  "status": "processing",
  "settled": false,
  "blocked": false,
  "readiness": {
    "raw": 3,
    "comprehension": 1,
    "consolidation": 0,
    "parked": 0
  }
}
```

- **Gate on `settled`, not on `status`.** Settlement is project-wide: `settled` is true only when the whole queue has drained with nothing parked, so a query never reads a half-written graph.
- `readiness` counts the points still sitting in each pipeline stage. Zeros everywhere except `parked` means the queue is drained.
- `blocked: true` means everything left is parked. Stop polling and tell us rather than waiting out a timeout.
- `status` is `completed`, `parked` or `processing` for this one point. The queue is FIFO, so the **last** ingestion id of a feed covers the whole feed.
- An unknown id returns **404** with code `not-found`.

### DELETE /api/v1/ingest/{ingestionId}

Forget a source. The point is removed and everything only it supported is erased with it: its mentions, embeddings, and any entities or edges nothing else corroborates. Knowledge corroborated by other sources survives on those sources. Returns **204** with no body; an unknown id returns **404**.

### POST /api/v1/recall

Returns ranked evidence with its sources and no generated text, for running a separate model over the context.

| Field | Description |
| --- | --- |
| `query` (string, required) | A natural-language question. Retrieval plans its own traversals from it. |
| `maxTokens` (integer) | A token budget for the returned evidence rather than a result count. Evidence is included most-relevant-first until the budget is spent. Omit for everything. |
| `limit` (integer) | Cap on evidence matches returned. |
| `queryTimestamp` (ISO 8601) | Anchors relative-time reasoning ("last week") to a point in the past. Use it when replaying a historical conversation. |
| `includeTimeline` (boolean) | Include the dated relationship record for the subject, returned as `timeline`. |
| `verbatim` (boolean) | Return raw source excerpts instead of the distilled form. Ordering questions need this, because only the raw corpus preserves within-source order. |
| `tag` (string) | Free-form correlation tag, echoed into usage records. |
| `projectId` (integer) | Names the project when the key's organization has several. |

```200ok
{
  "results": [
    { "entityId": "0f2a66d1-9c3b-4a7e-8d15-6b4e2c9f1a03",
      "name": "Acme pilot", "type": "Project", "score": 0.92, "via": null }
  ],
  "evidence": [
    { "source": "Email from Nadia", "sourceTitle": null,
      "date": "2026-07-28T16:00:00Z",
      "excerpt": "Budget for the Acme pilot moved to 40k.", "score": 0.9 }
  ],
  "truncated": false,
  "intent": "Lookup",
  "degradedArms": [],
  "usage": {
    "recallTokensIn": 812,
    "recallTokensOut": 96,
    "recallCostUsd": 0.000214
  }
}
```

- Every `evidence` entry carries its `source`, `date`, `excerpt` and ranking `score`: enough for your model to cite and for you to audit.
- `degradedArms` names any retrieval arm that stayed degraded after its retry, which tells a partial search apart from a complete one that found little. An empty array means every arm ran.
- `truncated` means the token budget cut the result set.
- With `includeTimeline`, the response also carries `relationships` and `timeline`: dated records with `from`, `type`, `to`, `validFrom` and `validTo`.

### POST /api/v1/answer

Recall plus a grounded answer. It shares /recall's retrieval fields and adds three of its own.

| Field | Description |
| --- | --- |
| `query` (string, required) | The question to answer. |
| `mode` (string) | Only `pipeline` (the default) is available: retrieve, then answer. Sending `agent` is refused with `agent-mode-unavailable`; an agentic loop is on the roadmap below. |
| `responseSchema` (JSON Schema) | Force a structured answer. The conforming JSON is returned in `structuredAnswer`. An invalid schema is refused with `invalid-response-schema`. |
| `budget` (string) | Named context budget for the answerer. |
| `queryTimestamp` (ISO 8601) | Anchors relative-time reasoning to a point in the past, exactly as on /recall. |
| `includeTimeline` (boolean) | Include the complete dated record for the subject, not only the top matches. |
| `verbatim` (boolean) | Answer from raw source excerpts instead of the distilled form. |
| `tag` (string) | Free-form correlation tag, echoed into usage records. |
| `projectId` (integer) | Names the project when the key's organization has several. |

```200ok
{
  "answer": "40k. It moved from 32k on July 28.",
  "evidence": [
    { "marker": 1, "label": "Email from Nadia, 2026-07-28", "title": null }
  ],
  "abstained": false,
  "answerer": "gemini-3.5-flash",
  "recordKept": 12,
  "recordTotal": 12,
  "degradedArms": [],
  "usage": {
    "answerTokensIn": 2140,
    "answerTokensOut": 38,
    "answerCachedTokens": 1792,
    "answerCostUsd": 0.000431,
    "recallTokensIn": 812,
    "recallTokensOut": 96,
    "recallCostUsd": 0.000214
  }
}
```

- `abstained: true` means the memory did not hold the answer, so the model declined to generate one. Handle it as a normal outcome.
- `evidence` entries are numbered citations: `marker`, `label` and an optional `title`.
- `recordKept` and `recordTotal` separate "the record never loaded" from "the record loaded and the answer still missed": a retrieval problem versus a reasoning one.
- With `responseSchema`, the conforming JSON arrives in `structuredAnswer` alongside the prose `answer`.

### Entities, relationships and hops

> **Coming soon**
>
> Direct access to the graph the pipeline builds, rather than reaching it only through a question. Search and CRUD on entities, the memories behind one, the edges around it, and traversal out to a given depth.
>
> **None of these exist yet**, and the paths below are the intended shape rather than a contract. Everything they will expose is reachable today through `/api/v1/recall`, which returns the same evidence with its sources. Tell us which of them an integration needs: that is what decides the order they ship in.

| Route | What it will do |
| --- | --- |
| `GET /entities` | Search entities by text and type. The list view over the graph, for populating a UI rather than answering a question. |
| `POST /entities` | Create an entity directly, instead of waiting for extraction to derive it from content. |
| `GET /entities/{id}` | One entity with its three layers: the mentions it was built from, the dated observations drawn out of them, and the value that holds now. |
| `PATCH /entities/{id}` | Correct or set values on an entity without re-ingesting the content it came from. |
| `DELETE /entities/{id}` | Remove an entity along with the facts derived from it. |
| `GET /entities/{id}/memories` | The memories behind one entity: verbatim mentions with their sources and timestamps, and the observations drawn from them. |
| `GET /entities/{id}/relationships` | The typed relationships into and out of an entity, with the dates they hold for. |
| `GET /entities/{id}/hops` | Traverse outward to a given depth, for walking a neighbourhood of the graph rather than querying it. |

### POST /configurations

> **Coming soon**
>
> Project configuration through the API: the custom ontology, the audiences a data point can be scoped to, and the defaults applied to ingestion. **This endpoint does not exist yet**, and the request shape is not settled, so do not build against the name.
>
> During early access we apply the same configuration by hand. Tell us what needs setting up when requesting access, or any time after.