> For the complete documentation index, see [llms.txt](https://docs.monolithforensics.com/monolith/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.monolithforensics.com/monolith/monolith-api/notes-api/note-object-links.md).

# Note Object Links

Notes can be linked to other Monolith objects — evidence items, tasks, timeline events, acquisitions, or the case itself. Links make a note discoverable from the linked object (and vice versa: `GET /v1/notes?object_id=...`).

Supported `object_type` values: `timeline_event`, `task`, `case`, `evidence`, `acquisition`.

## Endpoints

* `GET /v1/notes/object-links` — list links
* `POST /v1/notes/object-links` — create a link
* `DELETE /v1/notes/object-links/{id}` or `DELETE /v1/notes/object-links?note_uuid=...&object_id=...` — delete a link

***

## List object links

```http
GET /v1/notes/object-links
```

### Query parameters

All optional.

| Parameter     | Type   | Default | Description                      |
| ------------- | ------ | ------- | -------------------------------- |
| `id`          | number | —       | A single link by its numeric id. |
| `note_uuid`   | string | —       | Links belonging to this note.    |
| `object_id`   | string | —       | Links pointing at this object.   |
| `object_type` | string | —       | Filter by object type.           |
| `page`        | number | `1`     | Page number (1-based).           |
| `page_size`   | number | `3000`  | Results per page, max `3000`.    |

### Response — `200 OK`

```json
{
  "data": [
    {
      "id": 314,
      "note_uuid": "0f8fad5b-d9cb-469f-a165-70867728950e",
      "object_id": "e7c40f6e-2f19-4b52-9d7a-52a5a24c3f10",
      "object_type": "evidence",
      "object_name": "EV-2026-0042-001",
      "created_on": "2026-08-03T14:25:00Z"
    }
  ],
  "page": 1,
  "next_page": null,
  "page_size": 3000,
  "total": 1
}
```

`object_name` is the human-readable name of the linked object (evidence number, task name, ...), resolved at read time. It is `null` if the target object no longer exists.

```python
response = session.get(f"{BASE_URL}/notes/object-links", params={
    "note_uuid": "0f8fad5b-d9cb-469f-a165-70867728950e",
})
for link in response.json()["data"]:
    print(f"[{link['id']}] {link['object_type']}: {link['object_name']}")
```

***

## Create an object link

```http
POST /v1/notes/object-links
Content-Type: application/json
```

### Request body

| Field         | Type   | Required | Description                                                     |
| ------------- | ------ | -------- | --------------------------------------------------------------- |
| `note_uuid`   | string | **yes**  | UUID of the note.                                               |
| `object_id`   | string | **yes**  | UUID of the target object.                                      |
| `object_type` | string | **yes**  | `timeline_event`, `task`, `case`, `evidence`, or `acquisition`. |

```json
{
  "note_uuid": "0f8fad5b-d9cb-469f-a165-70867728950e",
  "object_id": "e7c40f6e-2f19-4b52-9d7a-52a5a24c3f10",
  "object_type": "evidence"
}
```

### Response — `201 Created` (or `200 OK` if the link already existed)

Creating a link that already exists is not an error: the call succeeds with status `200` and `"created": false`.

```json
{
  "success": true,
  "created": true,
  "message": "Note object link created",
  "data": {
    "id": 314,
    "note_uuid": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "object_id": "e7c40f6e-2f19-4b52-9d7a-52a5a24c3f10",
    "object_type": "evidence",
    "object_name": "EV-2026-0042-001",
    "created_on": "2026-08-03T14:25:00Z"
  }
}
```

```python
response = session.post(f"{BASE_URL}/notes/object-links", json={
    "note_uuid": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "object_id": "e7c40f6e-2f19-4b52-9d7a-52a5a24c3f10",
    "object_type": "evidence",
})
body = response.json()
if body["created"]:
    print(f"Linked (link id {body['data']['id']})")
else:
    print("Was already linked")
```

***

## Delete an object link

Target a single link by its numeric id, **or** by the note + object pair. Deleting by note alone is intentionally not supported — that would silently remove every link the note has.

```http
DELETE /v1/notes/object-links/{id}
DELETE /v1/notes/object-links?note_uuid={note_uuid}&object_id={object_id}
```

### Response — `200 OK`

```json
{
  "success": true,
  "message": "Note object link deleted",
  "deleted_count": 1
}
```

```python
# By link id
session.delete(f"{BASE_URL}/notes/object-links/314").raise_for_status()

# By note + object pair
session.delete(f"{BASE_URL}/notes/object-links", params={
    "note_uuid": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "object_id": "e7c40f6e-2f19-4b52-9d7a-52a5a24c3f10",
}).raise_for_status()
```

***

## Errors

| Status | Body                                                         | Cause                                                       |
| ------ | ------------------------------------------------------------ | ----------------------------------------------------------- |
| `400`  | `{"message": "Invalid request body", "errors": [...]}`       | Missing field or invalid `object_type` on create.           |
| `400`  | `{"message": "Invalid request parameters", "errors": [...]}` | Delete without an `id` or a `note_uuid` + `object_id` pair. |
| `404`  | `{"message": "Note not found"}`                              | Create targeting a nonexistent note.                        |
| `404`  | `{"message": "Note object link not found"}`                  | Delete targeting a nonexistent link.                        |
| `401`  | `Unauthorized`                                               | Missing or invalid API key.                                 |
