> For the complete documentation index, see [llms.txt](https://docs.inrupt.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.inrupt.com/ess/services/service-search/search-api.md).

# Search API

{% hint style="success" %}
Added in version 3.2.0
{% endhint %}

The ESS [Search Service](/ess/services/service-search.md) provides a set of REST endpoints for searching, discovering, and managing indexed Pod content. All endpoints require authentication and are scoped to the authenticated agent.

## Base URL

```none
https://search.<ESS Domain>/api/search
```

## `POST /api/search`

Performs a full-text search over the authenticated agent's indexed Pod content. Supports hybrid (keyword + semantic), keyword-only, and semantic-only search modes.

In hybrid mode (the default), the service queries both OpenSearch (BM25 keyword search) and pgvector (semantic vector search) and merges results using Reciprocal Rank Fusion (RRF).

### Input

| Field         | Value                                        |
| ------------- | -------------------------------------------- |
| Endpoint      | **`https://search.{ESS Domain}/api/search`** |
| Method        | **`POST`**                                   |
| Authorization | Bearer access token                          |
| Content-Type  | **`application/json`**                       |
| Payload       | Search request object                        |

### Request Body

| Field               | Type            | Required | Description                                                                                             |
| ------------------- | --------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| **`query`**         | String          | Yes      | The search query text. 1–1000 characters.                                                               |
| **`mode`**          | String          | No       | Search mode: **`hybrid`** (default), **`keyword`**, or **`semantic`**.                                  |
| **`scope`**         | Array of String | No       | Container paths to restrict search to. Max 20 items, each max 500 characters. Must start with **`/`**.  |
| **`exclude`**       | Array of String | No       | Container paths to exclude from search. Max 20 items, each max 500 characters. Must start with **`/`**. |
| **`limit`**         | Integer         | No       | Maximum number of results to return. 1–100. Default: **`10`**.                                          |
| **`resourceTypes`** | Array of String | No       | Filter results by resource type. Max 20 items. See [Resource Types](#resource-types).                   |

### Example Request

```http
POST /api/search HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "query": "quarterly revenue report",
  "mode": "hybrid",
  "limit": 5,
  "resourceTypes": ["document"],
  "scope": ["/financial/reports/"]
}
```

### Output

Returns a **`SearchResponse`** containing matching chunks ranked by relevance.

| Field                | Type                  | Description                                                                                                                           |
| -------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **`results`**        | Array of SearchResult | The matching content chunks, ranked by score.                                                                                         |
| **`query`**          | String                | The query string, echoed back.                                                                                                        |
| **`processingTime`** | Integer               | Processing time in milliseconds.                                                                                                      |
| **`estimatedTotal`** | Integer               | Approximate total number of matching results. May be **`null`**.                                                                      |
| **`hasMore`**        | Boolean               | Whether additional results exist beyond the returned set. If **`true`**, increase the **`limit`** parameter to retrieve more results. |

Each **`SearchResult`** contains:

| Field                | Type         | Description                                                                                                  |
| -------------------- | ------------ | ------------------------------------------------------------------------------------------------------------ |
| **`resourceUrl`**    | String (URI) | The URL of the source resource.                                                                              |
| **`resourceType`**   | String       | The resource type label assigned during indexing. See [Resource Types](#resource-types).                     |
| **`chunkText`**      | String       | The matching text chunk.                                                                                     |
| **`chunkIndex`**     | Integer      | The position of this chunk within the source resource.                                                       |
| **`score`**          | Number (0–1) | The overall relevance score.                                                                                 |
| **`scoreBreakdown`** | Object       | Breakdown of the score by search backend. See below.                                                         |
| **`metadata`**       | Object       | Resource metadata including **`filename`**, **`contentType`**, **`container`**, and **`indexed`** timestamp. |

The **`scoreBreakdown`** object contains:

| Field               | Type   | Description                                                                                                                                                                                                                                                                 |
| ------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`bm25Score`**     | Number | The BM25 keyword search score. **`null`** in semantic-only mode.                                                                                                                                                                                                            |
| **`semanticScore`** | Number | The semantic similarity score. **`null`** in keyword-only mode.                                                                                                                                                                                                             |
| **`rrfScore`**      | Number | The Reciprocal Rank Fusion score. Present only in hybrid mode.                                                                                                                                                                                                              |
| **`matchSource`**   | String | Which backend(s) matched: **`keyword`**, **`semantic`**, or **`both`**. Check this field to detect when a hybrid search has silently degraded to keyword-only or semantic-only — see [Search Modes](/ess/services/service-search.md#search-modes) for degradation behavior. |

### Example Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "results": [
    {
      "resourceUrl": "https://storage.example.com/pods/alice/financial/reports/q3-2026.pdf",
      "resourceType": "document",
      "chunkText": "Total revenue for Q3 2026 was $4.2M, representing a 15% increase over Q2...",
      "chunkIndex": 3,
      "score": 0.87,
      "scoreBreakdown": {
        "bm25Score": 0.82,
        "semanticScore": 0.91,
        "rrfScore": 0.87,
        "matchSource": "both"
      },
      "metadata": {
        "filename": "q3-2026.pdf",
        "container": "/financial/reports/",
        "indexed": "2026-07-15T10:30:00Z"
      }
    }
  ],
  "query": "quarterly revenue report",
  "processingTime": 145,
  "estimatedTotal": 12,
  "hasMore": true
}
```

## `POST /api/search/query`

Queries indexed content using metadata filters, with optional semantic search. Supports filtering, sorting, deduplication, and field selection.

### Input

| Field         | Value                                              |
| ------------- | -------------------------------------------------- |
| Endpoint      | **`https://search.{ESS Domain}/api/search/query`** |
| Method        | **`POST`**                                         |
| Authorization | Bearer access token                                |
| Content-Type  | **`application/json`**                             |
| Payload       | Metadata query request object                      |

### Request Body

| Field                  | Type                             | Required | Description                                                                                                              |
| ---------------------- | -------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| **`resourceTypes`**    | Array of String                  | No       | Filter by resource type. Max 20 items. Pattern: **`^[a-zA-Z][a-zA-Z0-9_:.-]*$`**. See [Resource Types](#resource-types). |
| **`filters`**          | Array of MetadataFilter          | No       | AND-combined metadata filters. Max 20. See [Filter Operators](#filter-operators).                                        |
| **`filtersOr`**        | Array of Array of MetadataFilter | No       | OR groups of AND-combined filters. Max 5 outer groups, each 1–10 filters.                                                |
| **`metadataContains`** | Object                           | No       | Key-value pairs that must exist in the resource metadata.                                                                |
| **`query`**            | String                           | No       | Optional semantic search query to combine with filters. Max 1000 characters.                                             |
| **`dedupKey`**         | String                           | No       | Metadata field to deduplicate results by. Pattern: **`^[a-zA-Z]\w*$`**.                                                  |
| **`sort`**             | Array of SortField               | No       | Sort order. Max 3 fields. See below.                                                                                     |
| **`includeTotal`**     | Boolean                          | No       | Whether to include the total count of matching results.                                                                  |
| **`limit`**            | Integer                          | No       | Maximum results. 1–1000. Default: **`100`**.                                                                             |
| **`selectFields`**     | Array of String                  | No       | Metadata fields to include in results. Max 20. If unset, all fields are returned.                                        |
| **`includeChunkText`** | Boolean                          | No       | Whether to include the chunk text in results.                                                                            |

Each **`MetadataFilter`** contains:

| Field               | Type    | Required | Description                                                                                                                                     |
| ------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **`field`**         | String  | Yes      | The metadata field to filter on. Pattern: **`^[a-zA-Z]\w*$`**.                                                                                  |
| **`operator`**      | String  | Yes      | The filter operator. See [Filter Operators](#filter-operators).                                                                                 |
| **`value`**         | Any     | Depends  | The filter value. Not required for **`exists`** / **`notExists`** operators.                                                                    |
| **`valueType`**     | String  | No       | Type hint for the value: **`string`**, **`number`**, or **`date`**.                                                                             |
| **`absoluteValue`** | Boolean | No       | If **`true`**, applies **`ABS()`** to the field value before comparison. Only valid when **`valueType`** is **`number`**. Default: **`false`**. |

Each **`SortField`** contains:

| Field           | Type   | Required | Description                                           |
| --------------- | ------ | -------- | ----------------------------------------------------- |
| **`field`**     | String | Yes      | The metadata field to sort by.                        |
| **`direction`** | String | No       | Sort direction: **`asc`** or **`desc`** (default).    |
| **`valueType`** | String | No       | Type hint: **`string`**, **`number`**, or **`date`**. |

#### Filter Operators

| Operator        | Description                                | Requires Value |
| --------------- | ------------------------------------------ | -------------- |
| **`eq`**        | Equals                                     | Yes            |
| **`neq`**       | Not equals                                 | Yes            |
| **`gt`**        | Greater than                               | Yes            |
| **`gte`**       | Greater than or equal to                   | Yes            |
| **`lt`**        | Less than                                  | Yes            |
| **`lte`**       | Less than or equal to                      | Yes            |
| **`like`**      | Pattern match (case-insensitive substring) | Yes            |
| **`in`**        | Value is in the provided array             | Yes (array)    |
| **`nin`**       | Value is not in the provided array         | Yes (array)    |
| **`exists`**    | Field exists in metadata                   | No             |
| **`notExists`** | Field does not exist in metadata           | No             |

### Example Request

```http
POST /api/search/query HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "resourceTypes": ["document"],
  "filters": [
    {"field": "department", "operator": "eq", "value": "finance"},
    {"field": "year", "operator": "gte", "value": 2025, "valueType": "number"}
  ],
  "sort": [{"field": "year", "direction": "desc", "valueType": "number"}],
  "dedupKey": "filename",
  "limit": 20,
  "includeTotal": true
}
```

### Output

Returns a **`MetadataQueryResponse`**:

| Field                | Type                    | Description                                                                                                                           |
| -------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **`results`**        | Array of MetadataResult | The matching results.                                                                                                                 |
| **`total`**          | Integer                 | Total matching results. **`null`** if **`includeTotal`** was not set.                                                                 |
| **`hasMore`**        | Boolean                 | Whether additional results exist beyond the returned set. If **`true`**, increase the **`limit`** parameter to retrieve more results. |
| **`processingTime`** | Integer                 | Processing time in milliseconds.                                                                                                      |

Each **`MetadataResult`** contains:

| Field              | Type         | Description                                                                              |
| ------------------ | ------------ | ---------------------------------------------------------------------------------------- |
| **`resourceUrl`**  | String (URI) | The URL of the source resource.                                                          |
| **`resourceType`** | String       | The resource type label assigned during indexing. See [Resource Types](#resource-types). |
| **`chunkText`**    | String       | The text chunk. Present only if **`includeChunkText`** was set.                          |
| **`chunkIndex`**   | Integer      | The chunk position within the resource.                                                  |
| **`score`**        | Number       | The relevance score. **`null`** when no **`query`** was provided.                        |
| **`metadata`**     | Object       | The resource metadata, filtered by **`selectFields`** if specified.                      |

### Example Response

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "results": [
    {
      "resourceUrl": "https://storage.example.com/pods/alice/finance/budget-2026.pdf",
      "resourceType": "document",
      "chunkIndex": 0,
      "score": null,
      "metadata": {
        "department": "finance",
        "year": 2026,
        "filename": "budget-2026.pdf"
      }
    }
  ],
  "total": 8,
  "hasMore": false,
  "processingTime": 52
}
```

## `POST /api/search/query/aggregate`

Performs a group-by aggregation on a metadata field across the authenticated agent's indexed content.

### Input

| Field         | Value                                                        |
| ------------- | ------------------------------------------------------------ |
| Endpoint      | **`https://search.{ESS Domain}/api/search/query/aggregate`** |
| Method        | **`POST`**                                                   |
| Authorization | Bearer access token                                          |
| Content-Type  | **`application/json`**                                       |
| Payload       | Metadata aggregation request object                          |

### Request Body

| Field                  | Type                             | Required | Description                                                                                      |
| ---------------------- | -------------------------------- | -------- | ------------------------------------------------------------------------------------------------ |
| **`groupBy`**          | String                           | Yes      | The metadata field to group by. Pattern: **`^[a-zA-Z]\w*$`**.                                    |
| **`resourceTypes`**    | Array of String                  | No       | Filter by resource type before aggregating. Max 20 items. See [Resource Types](#resource-types). |
| **`filters`**          | Array of MetadataFilter          | No       | AND-combined metadata filters. Max 20.                                                           |
| **`filtersOr`**        | Array of Array of MetadataFilter | No       | OR groups of AND-combined filters. Max 5 outer, 1–10 inner.                                      |
| **`metadataContains`** | Object                           | No       | Key-value pairs that must exist in the resource metadata.                                        |
| **`limit`**            | Integer                          | No       | Maximum number of buckets. 1–1000. Default: **`100`**.                                           |
| **`includeTotal`**     | Boolean                          | No       | Whether to include the total count across all buckets.                                           |

### Example Request

```http
POST /api/search/query/aggregate HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "groupBy": "department",
  "resourceTypes": ["document"],
  "includeTotal": true
}
```

### Output

Returns a **`MetadataAggregationResponse`**:

| Field                | Type                    | Description                                                                   |
| -------------------- | ----------------------- | ----------------------------------------------------------------------------- |
| **`buckets`**        | Array of MetadataBucket | The aggregation buckets.                                                      |
| **`total`**          | Integer                 | Total count across all buckets. **`null`** if **`includeTotal`** was not set. |
| **`processingTime`** | Integer                 | Processing time in milliseconds.                                              |

Each **`MetadataBucket`** contains:

| Field       | Type    | Description                          |
| ----------- | ------- | ------------------------------------ |
| **`value`** | String  | The group-by field value.            |
| **`count`** | Integer | The number of chunks in this bucket. |

### Example Response

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "buckets": [
    {"value": "finance", "count": 342},
    {"value": "engineering", "count": 218},
    {"value": "legal", "count": 95}
  ],
  "total": 655,
  "processingTime": 38
}
```

## `POST /api/search/facets`

Returns faceted counts grouped by one or more dimensions (resource type or container). Optionally scoped by a search query.

### Input

| Field         | Value                                               |
| ------------- | --------------------------------------------------- |
| Endpoint      | **`https://search.{ESS Domain}/api/search/facets`** |
| Method        | **`POST`**                                          |
| Authorization | Bearer access token                                 |
| Content-Type  | **`application/json`**                              |
| Payload       | Facet request object                                |

### Request Body

| Field               | Type            | Required | Description                                                                                           |
| ------------------- | --------------- | -------- | ----------------------------------------------------------------------------------------------------- |
| **`facets`**        | Array of String | Yes      | Facet dimensions to compute. Values: **`resourceType`**, **`container`**. Min 1, max 3.               |
| **`query`**         | String          | No       | Optional search query to scope facet counts. Max 1000 characters.                                     |
| **`scope`**         | Array of String | No       | Container paths to restrict to. Max 20 items.                                                         |
| **`exclude`**       | Array of String | No       | Container paths to exclude. Max 20 items.                                                             |
| **`resourceTypes`** | Array of String | No       | Filter by resource type before computing facets. Max 20 items. See [Resource Types](#resource-types). |
| **`dateRange`**     | Object          | No       | Filter by date range. Contains **`from`** and/or **`to`** (ISO 8601 date-time).                       |

### Example Request

```http
POST /api/search/facets HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "facets": ["resourceType", "container"],
  "scope": ["/documents/"]
}
```

### Output

Returns a **`FacetResponse`**:

| Field         | Type    | Description                                                           |
| ------------- | ------- | --------------------------------------------------------------------- |
| **`total`**   | Integer | Total number of matching chunks.                                      |
| **`query`**   | String  | The query string, if provided. **`null`** otherwise.                  |
| **`facets`**  | Object  | Map of facet dimension names to arrays of buckets.                    |
| **`partial`** | Boolean | Whether the facet counts are approximate (due to timeouts or limits). |

Each facet bucket contains:

| Field       | Type    | Description                                                      |
| ----------- | ------- | ---------------------------------------------------------------- |
| **`value`** | String  | The facet value (e.g., a resource type label or container path). |
| **`count`** | Integer | The number of matching chunks.                                   |

### Example Response

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "total": 1250,
  "query": null,
  "facets": {
    "resourceType": [
      {"value": "document", "count": 830},
      {"value": "email", "count": 420}
    ],
    "container": [
      {"value": "/documents/reports/", "count": 600},
      {"value": "/documents/memos/", "count": 650}
    ]
  },
  "partial": false
}
```

## `POST /api/search/resources`

Looks up index status and metadata for specific resource URLs. Use this to check whether resources have been indexed and when they were last updated.

### Input

| Field         | Value                                                  |
| ------------- | ------------------------------------------------------ |
| Endpoint      | **`https://search.{ESS Domain}/api/search/resources`** |
| Method        | **`POST`**                                             |
| Authorization | Bearer access token                                    |
| Content-Type  | **`application/json`**                                 |
| Payload       | Resource lookup request object                         |

### Request Body

| Field              | Type                  | Required | Description                                                             |
| ------------------ | --------------------- | -------- | ----------------------------------------------------------------------- |
| **`resourceUrls`** | Array of String (URI) | Yes      | The resource URLs to look up. Min 1, max 100. Each max 2048 characters. |

### Example Request

```http
POST /api/search/resources HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "resourceUrls": [
    "https://storage.example.com/pods/alice/reports/q3-2026.pdf",
    "https://storage.example.com/pods/alice/reports/q2-2026.pdf"
  ]
}
```

### Output

Returns a **`ResourceLookupResponse`**:

| Field           | Type                  | Description                                |
| --------------- | --------------------- | ------------------------------------------ |
| **`resources`** | Array of ResourceInfo | Information about each requested resource. |

Each **`ResourceInfo`** contains:

| Field              | Type              | Description                                                                              |
| ------------------ | ----------------- | ---------------------------------------------------------------------------------------- |
| **`resourceUrl`**  | String (URI)      | The resource URL.                                                                        |
| **`indexed`**      | Boolean           | Whether the resource is currently indexed.                                               |
| **`resourceType`** | String            | The resource type label assigned during indexing. See [Resource Types](#resource-types). |
| **`chunkCount`**   | Integer           | The number of indexed chunks for this resource.                                          |
| **`lastIndexed`**  | String (ISO 8601) | When the resource was last indexed. **`null`** if not indexed.                           |
| **`metadata`**     | Object            | Additional resource metadata.                                                            |

### Example Response

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "resources": [
    {
      "resourceUrl": "https://storage.example.com/pods/alice/reports/q3-2026.pdf",
      "indexed": true,
      "resourceType": "document",
      "chunkCount": 12,
      "lastIndexed": "2026-07-15T10:30:00Z",
      "metadata": {"filename": "q3-2026.pdf"}
    },
    {
      "resourceUrl": "https://storage.example.com/pods/alice/reports/q2-2026.pdf",
      "indexed": false,
      "resourceType": null,
      "chunkCount": 0,
      "lastIndexed": null,
      "metadata": {}
    }
  ]
}
```

## `GET /api/search/stats`

Returns index statistics for the authenticated agent, including total chunk and resource counts and a breakdown by resource type.

### Input

| Field         | Value                                              |
| ------------- | -------------------------------------------------- |
| Endpoint      | **`https://search.{ESS Domain}/api/search/stats`** |
| Method        | **`GET`**                                          |
| Authorization | Bearer access token                                |

### Output

Returns an **`IndexStats`** object:

| Field                   | Type              | Description                                                                 |
| ----------------------- | ----------------- | --------------------------------------------------------------------------- |
| **`totalChunks`**       | Integer           | Total number of indexed chunks.                                             |
| **`totalResources`**    | Integer           | Total number of indexed resources.                                          |
| **`keywordChunks`**     | Integer           | Number of chunks in the keyword (OpenSearch) index.                         |
| **`vectorChunks`**      | Integer           | Number of chunks in the vector (pgvector) index.                            |
| **`lastIndexed`**       | String (ISO 8601) | When the most recent content was indexed. **`null`** if nothing is indexed. |
| **`embeddingModel`**    | String            | The embedding model used for vector indexing.                               |
| **`resourceBreakdown`** | Object            | Map of resource type to count.                                              |

### Example Response

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "totalChunks": 4523,
  "totalResources": 312,
  "keywordChunks": 4523,
  "vectorChunks": 4520,
  "lastIndexed": "2026-07-28T08:15:00Z",
  "embeddingModel": "BAAI/bge-small-en-v1.5",
  "resourceBreakdown": {
    "document": 180,
    "email": 95,
    "bank:transaction": 37
  }
}
```

## `DELETE /api/search/all`

Deletes all indexed content for the authenticated agent. This operation is irreversible.

### Input

| Field         | Value                                            |
| ------------- | ------------------------------------------------ |
| Endpoint      | **`https://search.{ESS Domain}/api/search/all`** |
| Method        | **`DELETE`**                                     |
| Authorization | Bearer access token                              |
| Content-Type  | **`application/json`**                           |
| Payload       | Deletion confirmation object                     |

### Request Body

| Field         | Type    | Required | Description                                 |
| ------------- | ------- | -------- | ------------------------------------------- |
| **`confirm`** | Boolean | Yes      | Must be **`true`** to confirm the deletion. |

### Example Request

```http
DELETE /api/search/all HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "confirm": true
}
```

### Output

Returns a **`DeletionResponse`**:

| Field              | Type    | Description                      |
| ------------------ | ------- | -------------------------------- |
| **`deletedCount`** | Integer | The number of chunks deleted.    |
| **`message`**      | String  | A human-readable status message. |

### Example Response

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "deletedCount": 4523,
  "message": "All indexed content deleted successfully"
}
```

## `DELETE /api/search/by-type`

Deletes all indexed content of a specific resource type for the authenticated agent.

### Input

| Field         | Value                                                |
| ------------- | ---------------------------------------------------- |
| Endpoint      | **`https://search.{ESS Domain}/api/search/by-type`** |
| Method        | **`DELETE`**                                         |
| Authorization | Bearer access token                                  |
| Content-Type  | **`application/json`**                               |
| Payload       | Type deletion request object                         |

### Request Body

| Field              | Type    | Required | Description                                                                                                                      |
| ------------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **`resourceType`** | String  | Yes      | The resource type to delete. 2–100 characters. Pattern: **`^[a-zA-Z][a-zA-Z0-9_:.-]*$`**. See [Resource Types](#resource-types). |
| **`confirm`**      | Boolean | Yes      | Must be **`true`** to confirm the deletion.                                                                                      |

### Example Request

```http
DELETE /api/search/by-type HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "resourceType": "document",
  "confirm": true
}
```

### Output

Returns a **`DeletionResponse`** with **`deletedCount`** and **`message`**.

## `DELETE /api/search/by-resource`

Deletes indexed content for specific resource URLs.

### Input

| Field         | Value                                                    |
| ------------- | -------------------------------------------------------- |
| Endpoint      | **`https://search.{ESS Domain}/api/search/by-resource`** |
| Method        | **`DELETE`**                                             |
| Authorization | Bearer access token                                      |
| Content-Type  | **`application/json`**                                   |
| Payload       | Resource deletion request object                         |

### Request Body

| Field              | Type                  | Required | Description                                                 |
| ------------------ | --------------------- | -------- | ----------------------------------------------------------- |
| **`resourceUrls`** | Array of String (URI) | Yes      | The resource URLs to delete from the index. Min 1, max 100. |
| **`confirm`**      | Boolean               | Yes      | Must be **`true`** to confirm the deletion.                 |

### Example Request

```http
DELETE /api/search/by-resource HTTP/1.1
Host: search.example.com
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "resourceUrls": [
    "https://storage.example.com/pods/alice/reports/outdated-report.pdf"
  ],
  "confirm": true
}
```

### Output

Returns a **`DeletionResponse`** with **`deletedCount`** and **`message`**.

## Resource Types

The **`resourceType`** field is a label that identifies what kind of content a resource represents. It is set during indexing and used for filtering, faceting, and deletion.

### How Resource Types Are Set

Resource types are assigned by the [Ingest Service](/ess/services/service-search/ingest-service.md) during indexing. The value depends on how content is indexed:

| Indexing Method                                    | How **`resourceType`** Is Set                                                                        | Examples                                    |
| -------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| Single-resource re-index (**`POST /api/reindex`**) | The value you provide in the **`resourceType`** request field. Defaults to **`unknown`** if omitted. | **`document`**, **`invoice`**, **`report`** |
| Bulk re-index (**`POST /api/reindex/all`**)        | Derived automatically from the resource's MIME content type in storage.                              | **`text/plain`**, **`application/pdf`**     |
| Real-time Kafka ingestion                          | Derived from the resource's RDF type URIs in the audit event.                                        | **`http://www.w3.org/ns/ldp#Resource`**     |
| Template-based indexing                            | Same as real-time Kafka ingestion (the type comes from the audit event, not the template).           | **`http://www.w3.org/ns/ldp#Resource`**     |

{% hint style="warning" %}
**Validation Constraints**

Search API endpoints validate **`resourceTypes`** values using the pattern **`^[a-zA-Z][a-zA-Z0-9_:.-]*$`**. Values containing forward slashes (such as MIME types or full RDF URIs) do not match this pattern.

To filter by resource type on search endpoints, use the single-resource re-index API (**`POST /api/reindex`**) to index resources with short, descriptive labels such as **`document`**, **`email`**, or **`bank:transaction`**. See [Ingest Service: Controlling Resource Types](/ess/services/service-search/ingest-service.md#controlling-resource-types) for a worked example.
{% endhint %}

### Choosing Resource Type Labels

When you control the indexing (via the single-resource re-index API), use short, descriptive labels. Labels can include an optional namespace prefix separated by a colon:

| Label                  | Description                                 |
| ---------------------- | ------------------------------------------- |
| **`document`**         | General documents (PDFs, Word files, text). |
| **`email`**            | Email messages.                             |
| **`bank:transaction`** | Financial transaction records (namespaced). |
| **`crm:contact`**      | CRM contact records (namespaced).           |
| **`invoice`**          | Invoice documents.                          |
| **`calendar-event`**   | Calendar entries.                           |

These labels are case-sensitive and must start with a letter. Use hyphens, underscores, colons, and dots to create readable, structured labels.
