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

# Datasource & custom properties

> Create a custom datasource, declare object types, property schemas, and the sub-datasource hierarchy used to filter results.

<Info>
  **Indexing API (BETA)** --- [Overview](/indexing-api/introduction) · [Datasource & properties](/indexing-api/setup-datasource) · [Index documents](/indexing-api/index-documents) · [Permissions](/indexing-api/permissions)
</Info>

## Overview

You do two things, in order:

1. **Create a datasource** --- declare **object types** (e.g. `wiki_page`, `account`) plus their **property definitions** (custom attributes such as `department`, `priority`), and optionally a tree of **sub-datasources** (used as the first/second-level filters in the search UI). Everything goes in a single `POST /datasources` call.
2. **Index documents** --- send the standard built-in fields plus a `custom_properties` array whose `name` values match the property definitions, and (optionally) reference a sub-datasource by its `key`.

Every document carries a set of **standard (built-in) fields** that amberSearch already knows how to index, display, and filter. On top of those you can define **custom attributes** (property definitions) for metadata specific to your datasource.

<Warning>
  Define properties and subs **before** you index documents that reference them. Adding or changing definitions later can delay or skew search behavior until affected documents are re-indexed (for example by re-sending them with `POST .../documents`).
</Warning>

## Naming rules (slugs)

Several identifiers in the Indexing API must be **slugs** in `word_word` form:

* **Datasource `name`** --- e.g. `internal_wiki`
* **Sub `key`** --- e.g. `engineering`, `runbooks`

The slug regex is `^[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*$`:

* lowercase letters and digits only,
* words separated by **single underscores** (no hyphens, no spaces, no leading digit).

For subs, the `key` is **auto-generated from `name`** if you omit it (e.g. `"HR Documents"` → `hr_documents`). The datasource `name` must always be supplied explicitly.

### Standard document fields

These fields are available on every document without any property definition. They use the same naming conventions as all amberSearch datasources:

| Field                 | Type   | Required | Description                                                                                                                                                                                           |
| --------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `datasource`          | string | Yes      | `name` of the target datasource.                                                                                                                                                                      |
| `id`                  | string | Yes      | Unique document identifier within the datasource. Alphanumeric, hyphens, underscores, dots.                                                                                                           |
| `title`               | string | Yes      | Document title shown in search results.                                                                                                                                                               |
| `body`                | object | Yes      | Searchable content --- either file binary (`binary_base64` + `mime_type`) or text (`text_content`). See [Content extraction](/indexing-api/index-documents#content-extraction-two-options).           |
| `file_type`           | enum   | Yes      | Semantic type of the document. See [File types](#file-types).                                                                                                                                         |
| `path_preview`        | string | Yes      | URL to open the document in its original application.                                                                                                                                                 |
| `last_modified`       | string | Yes      | ISO 8601 datetime when the document was last modified. Used for change detection.                                                                                                                     |
| `path`                | string | No       | Breadcrumb path inside the source system (e.g. `Engineering / Runbooks / Onboarding`).                                                                                                                |
| `author`              | string | No       | Free-form author identifier (e.g. an email or display name).                                                                                                                                          |
| `data_source_sub`     | string | No       | First-level sub-datasource **key** (must match a sub declared on the datasource). See [Sub-datasource hierarchy](#sub-datasource-hierarchy).                                                          |
| `data_source_sub_sub` | string | No       | Second-level sub-datasource **key** (child of `data_source_sub`).                                                                                                                                     |
| `permissions`         | object | No       | Access control. If omitted, the document is anonymous --- visible to everyone **registered on this datasource** (`POST /users`), not to your whole org. See [Permissions](/indexing-api/permissions). |
| `custom_properties`   | array  | No       | Your custom attributes. Each entry has a `name` (matching a [property definition](#custom-attributes-property-definitions)) and a `value`.                                                            |

For indexing examples, updates, deletes, and error handling see [Index documents](/indexing-api/index-documents).

### File types

`file_type` is **required** on every document and tells amberSearch how to render and treat the content. It must be one of:

`message`, `merge_request`, `issue`, `wiki`, `markdown`, `blog`, `content`, `timeline`, `email`, `file`, `directory`, `email_parent`, `issue_parent`, `wiki_parent`, `page`, `merge_request_parent`, `webpage`, `asset`.

Pick the value that best matches the source object (e.g. `wiki` for a wiki page, `file` for an arbitrary uploaded file, `webpage` for a scraped page, `email` for a mail message). The list is also exposed at runtime:

```bash theme={null}
curl -X GET "https://customerDomain.ambersearch.de/api/indexing/file-types" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

`GET /file-types` always returns **200 OK**.

### Sub-datasource hierarchy

amberSearch uses a three-level filter hierarchy for every datasource. These levels let users progressively narrow results:

| Level       | Field on the document | Source                 | Example UI label                   |
| ----------- | --------------------- | ---------------------- | ---------------------------------- |
| **Level 0** | `datasource`          | The datasource `name`. | "Internal Wiki" (= `display_name`) |
| **Level 1** | `data_source_sub`     | A top-level sub `key`. | "Engineering" (= sub `name`)       |
| **Level 2** | `data_source_sub_sub` | A child sub `key`.     | "Runbooks" (= sub `name`)          |

Subs are declared on the datasource (during creation, or later via the [sub endpoints](#manage-subs-after-creation)). On documents you reference subs **by their `key`** (the slug); amberSearch derives the human-readable label from the sub's `name` and the compound storage values automatically.

<Tip>
  If a `data_source_sub_sub` key is **unique** across the datasource, you can send it on a document **without** `data_source_sub` --- amberSearch will infer the parent. If the same child key appears under multiple parents the request fails with `AMBIGUOUS_DATA_SOURCE_SUB_SUB`; set `data_source_sub` explicitly in that case.
</Tip>

### Custom attributes (property definitions)

For metadata that goes beyond the built-in fields, you declare **property definitions** inside an **object definition** on the datasource and send matching **`custom_properties`** on each document.

Each property definition requires:

* **`name`** --- the **attribute key** you reference later in `custom_properties` when indexing documents.
* **`display_label`** --- the **attribute display name** shown in the search UI.

You also choose whether values should be **searchable** (`is_searchable`): when `true`, the property values are included in the full-text index so users can find documents by typing those values in a free-text query --- not only via structured filters.

## Create the datasource (with subs and property schemas)

`POST /api/indexing/datasources` --- include `subs` for the sub-datasource tree and `object_definitions` (with nested `property_definitions`) so amberSearch knows which metadata fields exist for each object type.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://customerDomain.ambersearch.de/api/indexing/datasources" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "internal_wiki",
      "display_name": "Internal Wiki",
      "subs": [
        {
          "name": "Engineering",
          "children": [
            { "name": "Runbooks" },
            { "name": "Architecture", "key": "architecture" }
          ]
        },
        {
          "key": "design",
          "name": "Design",
          "children": [{ "name": "Tokens" }]
        }
      ],
      "object_definitions": [
        {
          "name": "wiki_page",
          "display_label": "Wiki Page",
          "property_definitions": [
            {
              "name": "department",
              "display_label": "Department",
              "property_type": "TEXT",
              "is_searchable": true
            },
            {
              "name": "ticket_id",
              "display_label": "Ticket ID",
              "property_type": "TEXT",
              "is_searchable": true
            }
          ]
        }
      ]
    }'
  ```

  ```python Python theme={null}
  import requests

  requests.post(
      "https://customerDomain.ambersearch.de/api/indexing/datasources",
      headers={
          "Authorization": "Bearer YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      json={
          "name": "internal_wiki",
          "display_name": "Internal Wiki",
          "subs": [
              {
                  "name": "Engineering",
                  "children": [
                      {"name": "Runbooks"},
                      {"name": "Architecture", "key": "architecture"},
                  ],
              },
              {
                  "key": "design",
                  "name": "Design",
                  "children": [{"name": "Tokens"}],
              },
          ],
          "object_definitions": [
              {
                  "name": "wiki_page",
                  "display_label": "Wiki Page",
                  "property_definitions": [
                      {
                          "name": "department",
                          "display_label": "Department",
                          "property_type": "TEXT",
                          "is_searchable": True,
                      },
                      {
                          "name": "ticket_id",
                          "display_label": "Ticket ID",
                          "property_type": "TEXT",
                          "is_searchable": True,
                      },
                  ],
              }
          ],
      },
  ).raise_for_status()
  ```
</RequestExample>

**Response codes**

| Code             | When                                                                                    |
| ---------------- | --------------------------------------------------------------------------------------- |
| **201 Created**  | Datasource created (with the inline `subs` tree and `object_definitions`, if provided). |
| **409 Conflict** | A datasource with the same `name` already exists.                                       |

In the search UI filters this renders as:

```
Internal Wiki                          (Level 0 - datasource)
  ├── Engineering                      (Level 1 - data_source_sub: "engineering")
  │     ├── Runbooks                   (Level 2 - data_source_sub_sub: "runbooks")
  │     └── Architecture               (Level 2 - data_source_sub_sub: "architecture")
  └── Design                           (Level 1 - data_source_sub: "design")
        └── Tokens                     (Level 2 - data_source_sub_sub: "tokens")
```

### Datasource fields

| Field                | Required | Description                                                                                                                                                                                |
| -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`               | Yes      | Unique slug (`word_word`, max 128 chars). Lowercase letters and digits separated by single underscores.                                                                                    |
| `display_name`       | Yes      | Label shown in the search UI (max 255 chars).                                                                                                                                              |
| `icon_base64`        | No       | Base64-encoded icon image for the datasource (e.g. PNG, SVG).                                                                                                                              |
| `subs`               | No       | Initial sub-datasource tree. Each entry is a [`SubDefinition`](#sub-definition-fields). Children may be nested via `children` (max 2 levels: a top-level sub and one level of `children`). |
| `object_definitions` | No       | List of object types. Each has a `name`, optional `display_label`, and a list of [`property_definitions`](#property-definition-fields).                                                    |

### Sub definition fields

| Field        | Required | Description                                                                                                                                               |
| ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`       | Yes      | Display name shown in the search UI (max 512 chars). Unique per parent.                                                                                   |
| `key`        | No       | Machine-readable slug used on documents (`word_word`). Auto-generated from `name` if omitted (e.g. `"HR Documents"` → `hr_documents`). Unique per parent. |
| `parent_key` | No       | Key of the parent sub. Use this when adding a child sub via `POST .../subs` after creation.                                                               |
| `children`   | No       | Nested children (only used when **creating** a datasource with an initial tree).                                                                          |

<Note>
  Subs are limited to **two levels**: a top-level sub and one level of children. A child sub cannot have its own children.
</Note>

### Property definition fields

| Field           | Required | Description                                                                                                                                                                             |
| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`          | Yes      | **Attribute key** --- the identifier you use later in `custom_properties` on documents.                                                                                                 |
| `display_label` | Yes      | **Attribute display name** --- human-readable label shown in the search UI.                                                                                                             |
| `property_type` | No       | `TEXT` (default), `INTEGER`, `DATE`, `BOOLEAN`.                                                                                                                                         |
| `is_searchable` | No       | `false` (default). When `true`, property values are included in the full-text index so documents are findable by free-text queries on those values --- not only via structured filters. |

<Tip>
  **When to set `is_searchable: true`** --- Use it for values users might type in a search box, such as ticket IDs, project codes, or category names. Leave it `false` for purely structural metadata (e.g. internal database IDs or numeric scores) that should only be available as structured filters.
</Tip>

### Property types

| Type      | Description                                    |
| --------- | ---------------------------------------------- |
| `TEXT`    | String value.                                  |
| `INTEGER` | Numeric value.                                 |
| `DATE`    | Timestamp (use epoch **seconds** or ISO 8601). |
| `BOOLEAN` | `true` / `false`.                              |

Once your property definitions are in place, attach values on each document using `custom_properties` when [indexing](/indexing-api/index-documents#custom-properties-on-documents).

## Manage subs after creation

`POST /api/indexing/datasources/{name}/subs` adds a single sub to an existing datasource.

**Add a top-level sub** (auto-slug from `name`):

```bash theme={null}
curl -X POST "https://customerDomain.ambersearch.de/api/indexing/datasources/internal_wiki/subs" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Legal Documents" }'
```

**Add a child sub** by setting `parent_key` to an existing top-level sub key:

```bash theme={null}
curl -X POST "https://customerDomain.ambersearch.de/api/indexing/datasources/internal_wiki/subs" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Invoices",
    "parent_key": "finance"
  }'
```

**Response codes for `POST /datasources/{name}/subs`**

| Code              | When                                                                               |
| ----------------- | ---------------------------------------------------------------------------------- |
| **201 Created**   | Sub created.                                                                       |
| **404 Not Found** | Datasource not found, or the supplied `parent_key` does not match an existing sub. |
| **409 Conflict**  | A sub with the same `key` or `name` already exists under the same parent.          |

**Remove a sub** by its `key`. Children of a deleted sub are removed as well (cascade).

```bash theme={null}
curl -X DELETE "https://customerDomain.ambersearch.de/api/indexing/datasources/internal_wiki/subs/finance" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response codes for `DELETE /datasources/{name}/subs/{sub_key}`**

| Code               | When                                                                       |
| ------------------ | -------------------------------------------------------------------------- |
| **204 No Content** | Sub deleted (children cascade).                                            |
| **404 Not Found**  | Datasource not found, or no sub with that `key` exists for the datasource. |

<Warning>
  Deleting a sub does not delete documents that reference it; those documents will remain in the index but lose the sub-level filter binding until you re-index them with a valid `data_source_sub` / `data_source_sub_sub`.
</Warning>

## List, get, update, or delete a datasource

**List**

```bash theme={null}
curl -X GET "https://customerDomain.ambersearch.de/api/indexing/datasources" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Get one** (returns the datasource and its full sub tree)

```bash theme={null}
curl -X GET "https://customerDomain.ambersearch.de/api/indexing/datasources/internal_wiki" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Update** --- `PUT /api/indexing/datasources/{name}`. Only `display_name`, `icon_base64`, and `object_definitions` can be changed here. **Subs must be added or removed via the [sub endpoints](#manage-subs-after-creation).**

```bash theme={null}
curl -X PUT "https://customerDomain.ambersearch.de/api/indexing/datasources/internal_wiki" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "display_name": "Internal Wiki (renamed)" }'
```

**Delete** --- removes the datasource together with its subs, users, groups, memberships, and indexed documents.

<Warning>
  Cascade-deletes the datasource and all related data (subs, users, groups, memberships, and indexed Solr documents). Cannot be undone.
</Warning>

```bash theme={null}
curl -X DELETE "https://customerDomain.ambersearch.de/api/indexing/datasources/internal_wiki" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Response codes

| Endpoint                     | Code                        | When                                                                                                                                 |
| ---------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `GET /datasources`           | **200 OK**                  | Always (returns an empty list if none exist).                                                                                        |
| `GET /datasources/{name}`    | **200 OK**                  | Datasource found.                                                                                                                    |
|                              | **404 Not Found**           | No datasource with that `name`.                                                                                                      |
| `PUT /datasources/{name}`    | **200 OK**                  | Updated.                                                                                                                             |
|                              | **404 Not Found**           | Datasource not found.                                                                                                                |
| `DELETE /datasources/{name}` | **204 No Content**          | Datasource and all its Solr documents purged.                                                                                        |
|                              | **404 Not Found**           | Datasource not found.                                                                                                                |
|                              | **503 Service Unavailable** | The Solr purge step failed; the DB record was left intact — the operation is idempotent, so retry the request to finish the cascade. |

## Next step

<Card title="Index documents" icon="file-lines" href="/indexing-api/index-documents">
  Push and update documents and permissions.
</Card>
