> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.prolific.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.prolific.com/_mcp/server.

# Search filters by keyword

GET https://api.prolific.com/api/v1/filters/search/

Search titles, questions, descriptions, researcher help text, categories, subcategories, filter IDs and choice labels. Supports stemming, prefixes and accent-insensitive matching. Returns matching filters in ranked order with at most three matching choices per filter. Results are always paginated, with limit defaulting to 25 and offset to zero. meta.count always counts all matching filters before pagination. Workspace permissions apply before searching or counting. Study and participant-group filters remain searchable by metadata, but their choices are not loaded or searched. Their results have choices_included false and a link to browse choices separately. Available verification dimensions are returned when present in the filter catalogue, but are not searched. Self, next and previous links preserve the query and workspace context, including workspace_id. Ranking is conveyed only by array order. Pagination links follow shared API conventions; offsets beyond the matches return an empty page.

Reference: https://docs.prolific.com/api-reference/filters/search-filters

## Authentication

- `Authorization` header (required) (prefixed with ` Token  `) — The Prolific API uses API token to authenticate requests. You can create an API token directly from your settings. Your API token does not have an expiry date and carries full permission, so be sure to keep them secure. If your token is leaked, delete it and create a new one directly in the app. In your requests add `Authorization` header with the value `Token <your token>`.

## Request

### Query parameters

- `q` (string, required) — Trimmed, nonblank keyword query, at most 200 characters after trimming. Text is not a query language. Nonblank input with no searchable characters returns no matches.
- `limit` (integer, optional, default: 25) — Page size. Pagination applies even when this parameter is omitted.
- `offset` (integer, optional, default: 0) — Zero-based result offset. An offset beyond the collection returns an empty page.
- `workspace_id` (string, optional) — Workspace used to resolve accessible filters.

## Response

### 200

Search filters by keyword

- `results` (list of FilterSearchResult, required)
- `meta` (FilterSearchListMeta, required)
- `_links` (FilterSearchPaginationLinks, required)

## Errors

### 400 Bad Request Error

Missing, blank or oversized q; invalid limit or offset; or invalid workspace_id.

- `error` (ErrorDetail, required)

### 403 Forbidden Error

Workspace access denied.

- `error` (ErrorDetail, required)

### 404 Not Found Error

Requested workspace not found.

- `error` (ErrorDetail, required)

### 400 Client Request Error

Existing authentication, validation or permission error.

- `error` (ErrorDetail, required)

## Types

### FilterSearchResult

Stable descriptive summary independent of detailed. No complete choice maps, canonical maps or hierarchy trees are returned.

- `filter_id` (string, required)
- `title` (string, required)
- `description` (string, required)
- `question` (string, required, nullable)
- `category` (string, required, nullable)
- `subcategory` (string, required, nullable)
- `type` (enum, required)
  - Allowed values: `select`, `range`
- `data_type` (string, required)
- `matches` (list of FilterSearchTextMatch, required) — Text matches in the filter's own fields. Choice text matches are returned on individual choices.
- `choices_included` (boolean, required) — Whether choice data was loaded into the search catalogue. False for study and participant-group filters; their choices preview is omitted and _links.choices provides choice browsing. True does not imply that a filter has enumerable choices, such as range or free-entry filters.
- `choices` (FilterMatchingChoices, optional) — Omitted for filters without enumerable choices or when choices_included is false. Otherwise, a metadata-only match has an empty preview, matched zero and truncated false.
- `available_verification_dimensions` (list of string, optional) — Available verification dimensions from the question's filter metadata, matching GET /filters. Omitted when empty or absent. These values are not indexed or searched.
- `min` (FilterSearchResultMin, optional) — Existing minimum for range filters.
- `max` (FilterSearchResultMax, optional) — Existing maximum for range filters.
- `_links` (FilterSearchResultLinks, optional) — Present for enumerable choices, including study and participant-group filters whose choice data was not loaded. matching_choices is included only when choices match.

### FilterSearchListMeta

- `count` (integer, required) — All matching filters.

### FilterSearchPaginationLinks

- `self` (FilterSearchLink, required)
- `next` (FilterSearchLink, required)
- `previous` (FilterSearchLink, required)
- `last` (FilterSearchLink, required)

### ErrorDetail

- `status` (integer, required) — Status code as in the http standards
- `error_code` (integer, required) — Internal error code
- `title` (string, required) — Error title
- `detail` (ErrorDetailDetail, required) — Error detail
- `additional_information` (string, optional) — Optional extra information
- `traceback` (string, optional) — Optional debug information
- `interactive` (boolean, optional)

### FilterSearchTextMatch

- `field` (enum, required)
  - Allowed values: `filter_id`, `title`, `question`, `description`, `researcher_help_text`, `category`, `subcategory`
- `query_term` (string, required) — Original query term.
- `matched_text` (string, required) — Actual matched display text.
- `start` (integer, required) — Inclusive zero-based Unicode code-point position, not bytes or UTF-16 units.
- `end` (integer, required) — Exclusive zero-based Unicode code-point position.

### FilterMatchingChoices

Omitted for filters without enumerable choices or when choices_included is false. Otherwise, a metadata-only match has an empty preview, matched zero and truncated false.

- `total` (integer, required) — Total available choices in the filter, independent of the query.
- `matched` (integer, required) — All matching choices before preview truncation.
- `truncated` (boolean, required) — Whether matching choices were omitted.
- `results` (list of FilterChoiceSearchResult, required)

### FilterSearchResultMin

Existing minimum for range filters.

### FilterSearchResultMax

Existing maximum for range filters.

### FilterSearchResultLinks

Present for enumerable choices, including study and participant-group filters whose choice data was not loaded. matching_choices is included only when choices match.

- `choices` (FilterSearchLink, required)
- `matching_choices` (FilterSearchLink, optional)

### FilterSearchLink

- `href` (string, required, nullable) — Link URL, or null when no link is available.
- `title` (string, required)

### ErrorDetailDetail

Error detail

### FilterChoiceSearchResult

A selectable choice without children or ancestor paths.

- `id` (string, required) — Existing selection API choice key, always a string.
- `label` (string, required)
- `parent_id` (string, required, nullable) — ID of the immediate parent choice, or null for a root or flat choice.
- `num_children` (integer, required) — Number of immediate children in the filter hierarchy, independent of matches and pagination.
- `num_descendants` (integer, required) — Descendants in the filter hierarchy, excluding this choice. Independent of matches and pagination; flat choices and leaves return zero.
- `matches` (list of FilterChoiceTextMatch, required)

### ErrorDetailDetail2

All fields with validation errors

- `any_field` (list of string, optional) — Name of the field with a validation error and as a value an array with the error descriptions

### FilterChoiceTextMatch

Offsets apply directly to the returned label. Alias matches refer to the returned country label.

- `field` (enum, required)
  - Allowed values: `label`
- `query_term` (string, required) — Original query term.
- `matched_text` (string, required) — Actual matched display text.
- `start` (integer, required) — Inclusive zero-based Unicode code-point position, not bytes or UTF-16 units.
- `end` (integer, required) — Exclusive zero-based Unicode code-point position.

## Examples

**Response**

```json
{
  "results": [
    {
      "filter_id": "job-title",
      "title": "Job title",
      "description": "Select participants by occupation.",
      "question": "What is your job title?",
      "category": "Employment",
      "subcategory": null,
      "type": "select",
      "data_type": "ChoiceID",
      "matches": [],
      "choices_included": true,
      "choices": {
        "total": 5,
        "matched": 4,
        "truncated": true,
        "results": [
          {
            "id": "100",
            "label": "Software developers",
            "parent_id": null,
            "num_children": 3,
            "num_descendants": 3,
            "matches": [
              {
                "field": "label",
                "query_term": "developers",
                "matched_text": "developers",
                "start": 9,
                "end": 19
              }
            ]
          },
          {
            "id": "101",
            "label": "Application software developer",
            "parent_id": "100",
            "num_children": 0,
            "num_descendants": 0,
            "matches": [
              {
                "field": "label",
                "query_term": "developers",
                "matched_text": "developer",
                "start": 21,
                "end": 30
              }
            ]
          },
          {
            "id": "102",
            "label": "Systems software developer",
            "parent_id": "100",
            "num_children": 0,
            "num_descendants": 0,
            "matches": [
              {
                "field": "label",
                "query_term": "developers",
                "matched_text": "developer",
                "start": 17,
                "end": 26
              }
            ]
          }
        ]
      },
      "available_verification_dimensions": [
        "corroborated"
      ],
      "_links": {
        "choices": {
          "href": "https://api.prolific.com/api/v1/filters/job-title/choices/?limit=25&offset=0",
          "title": "Choices"
        },
        "matching_choices": {
          "href": "https://api.prolific.com/api/v1/filters/job-title/choices/search/?q=developers&limit=25&offset=0",
          "title": "Matching choices"
        }
      }
    }
  ],
  "meta": {
    "count": 1
  },
  "_links": {
    "self": {
      "href": "https://api.prolific.com/api/v1/filters/search/?q=developers",
      "title": "Current"
    },
    "next": {
      "href": null,
      "title": "Next"
    },
    "previous": {
      "href": null,
      "title": "Previous"
    },
    "last": {
      "href": "https://api.prolific.com/api/v1/filters/search/",
      "title": "Last"
    }
  }
}
```

**SDK Code**

```python
import requests

url = "https://api.prolific.com/api/v1/filters/search/"

querystring = {"q":"q"}

headers = {"Authorization": "Token <token>"}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

```javascript
const url = 'https://api.prolific.com/api/v1/filters/search/?q=q';
const options = {method: 'GET', headers: {Authorization: 'Token <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.prolific.com/api/v1/filters/search/?q=q"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Token <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.prolific.com/api/v1/filters/search/?q=q")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Token <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.prolific.com/api/v1/filters/search/?q=q")
  .header("Authorization", "Token <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.prolific.com/api/v1/filters/search/?q=q', [
  'headers' => [
    'Authorization' => 'Token <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.prolific.com/api/v1/filters/search/?q=q");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Token <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Token <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/filters/search/?q=q")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```