# Search for activities

`GET /api/search/activities/{searchText}`

- **Success:** `200 OK`
- **Products:** Operator (`FOH`), Consumer (`CONSUMER`) (any one of these products, not all)
- **Features:** Online Bookings (`ONLINEBOOK`), Online Joining (`ONLINEJOIN`), Front of House Generic Access (`FOHGENERIC`) (any one of these features, not all)

HTML version: [Search for activities](https://support.gladstonesoftware.cloud/reference/configuration/search-for-activities)

## Overview

Finds activities whose description contains the text you supply — a substring match for building an activity picker or a search box, not a way to look up an activity you already have the id of.

Be clear about what is actually searched, because the summary is misleading:

- **The activity id is not searched.** Only description text is matched, despite what "using activity ID" suggests. If you know the id, read the activity directly with [Get activity details](get-activity-details.md).
- **Which description depends on `descriptionOnly`.** By default the search runs against each activity's long description, falling back to the short description only for activities that have no long description. Set `descriptionOnly=true` to search the short description for every activity. An activity can therefore match under one setting and not the other.
- **Matching is a case-insensitive substring match** — `swim` finds "Swimming Lesson" and "Adult Swim". There is no prefix anchoring, no word-boundary handling, no fuzzy matching and no wildcards, so a stray space or a misspelling returns nothing.

**Classes and courses that have finished are excluded automatically.** A class or course is returned only if it has at least one booking starting in the future, judged in UTC at the moment of the request; ordinary activities are always returned. This means the same search can return fewer results tomorrow than today, with no change to the configuration.

**There is no paging and no result cap.** Every match is returned in one array, ordered alphabetically by `name`. A short or common search term against a large environment returns everything that matches, so keep search terms specific and expect the response size to grow with the estimate. There is no `total`, no cursor and no way to request a page.

An empty `searchText` is treated as an empty string rather than rejected, which matches every activity — so guard against sending one by accident.

## Endpoint

`GET {base_url}/api/search/activities/{searchText}`

`{base_url}` is the environment URL issued to your integration. See [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `searchText` | string | Yes | The text to look for inside the activity description, matched as a case-insensitive substring anywhere in the text. Which field is searched depends on `descriptionOnly`. No wildcards, no anchoring and no fuzzy matching, so partial words work but misspellings do not. Because it sits in the path, URL-encode it — a term containing a slash will otherwise fail to route. **An empty or missing value is not rejected**: it is treated as the empty string, which every activity contains, so you get every activity back. |

## Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `siteIds` | string | No | Restricts results to the given sites, as a **comma-separated string** in one parameter — `?siteIds=SITE1,SITE2`, not a repeated parameter. Site codes come from [Get all sites with optional filtering](get-all-sites-with-optional-filtering.md) and are upper-cased before matching, so casing does not matter. **A maximum of 5 sites** — a sixth is rejected with `400` and `A maximum of 5 SiteIds can be specified`. Every code must exist or the request fails with `400` and `One or more of the sites specified don't exist`; there is no partial filtering. Omit it to search every site, which is the default. |
| `webBookableOnly` | boolean | No | When `true`, returns only activities flagged as bookable online. **Defaults to `false`**, which returns everything that matches — including activities an operator only books over the counter. If you are building a consumer-facing journey you almost certainly want this `true`, because the default will show members activities they cannot book. |
| `descriptionOnly` | boolean | No | Switches which text is searched **and** what comes back in `description`. Default `false`: the search runs against the long description, falling back to the short description for activities that have no long description, and `description` in the response carries that same resolved text. Set `true` and both the search and the returned `description` use the short description for every activity, making `description` identical to `name`. This is the single most consequential parameter here — the same `searchText` can return different activities under each setting. |

## Sample request

```bash title="cURL"
curl -X GET '{base_url}/api/search/activities/{searchText}' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true'
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `[].id` | string | The activity's code, and the value to feed to the activity and booking endpoints — start with [Get activity details](get-activity-details.md). A string of at most 15 characters, operator-chosen rather than generated, and **stored upper-cased whatever casing was supplied**, so compare case-insensitively and upper-case any id you send back. It is also the key this activity's `translations` are stored against. |
| `[].description` | string | The longer descriptive text, intended for display to a member. **Its source depends on `descriptionOnly`**: with the default `false` it is the activity's long description, or the short description where no long one exists; with `true` it is always the short description, making this field identical to `name`. This is the text the search matched against, so highlighting the search term in it is safe under the default. |
| `[].name` | string | The activity's short name, up to 255 characters — the operator's own label, suitable for a list row. Always the short description regardless of `descriptionOnly`. Results are ordered alphabetically by this field. Not unique: the same activity name commonly exists at several sites as separate records with different ids, so show `siteId` alongside it or your users will see apparent duplicates. |
| `[].siteId` | string | The site this activity belongs to, matching the `id` used by the site endpoints. An activity record belongs to exactly one site, which is why the same activity offered at three venues appears as three results. Up to 15 characters. |
| `[].capacity` | integer (int32) | The maximum number of bookees the activity accepts. **`0` means no limit was ever set, not that the activity is full** — the field defaults to zero when no maximum is recorded, so do not treat `0` as "no places". This is a configured ceiling, not live availability: it tells you nothing about how many places remain on any given date. Use the availability and booking endpoints for that. |
| `[].translations` | array of object | Localised text for this activity, looked up by the activity `id`. Always present and never null; an empty array `[]` where nothing has been translated. Each entry translates one property into one culture, and coverage is not guaranteed — fall back to `name` and `description`. Note the search itself only matches the base text, so a member searching in their own language will not match a translated description. |
| `[].translations[].type` | string | Which property of the activity this entry translates, matching the field name. Up to 50 characters, stored verbatim from whatever the translation import supplied, so treat an unrecognised value as data to ignore rather than a field you have missed. |
| `[].translations[].culture` | string | The culture the `text` is written in, up to 20 characters. Compare it against the codes from [Retrieves all system-supported languages](retrieves-all-system-supported-languages-and-localization-settings.md) rather than assuming a fixed set. |
| `[].translations[].text` | string | The translated value, to be used in place of the base property named by `type` for the matching `culture`. Unbounded length. |

## Sample response

```json title="200 OK"
[
  {
    "id": "string",
    "description": "string",
    "name": "string",
    "siteId": "string",
    "capacity": 1,
    "translations": [
      {
        "type": "string",
        "culture": "string",
        "text": "string"
      }
    ]
  }
]
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `200` | OK | Success. A search that matches nothing returns `200` with an empty JSON array `[]` — not `204` and not `404`. |
| `400` | Bad request | More than five site codes in `siteIds`. Body: `A maximum of 5 SiteIds can be specified`. |
| `400` | Bad request | One or more codes in `siteIds` does not match a site. Body: `One or more of the sites specified don't exist`. The whole request fails; the valid codes are not searched. |
| `500` | Internal server error | An unexpected server-side failure running the search or looking up its translations. The response has no body. A very broad `searchText` against a large environment produces an unbounded result set, so treat a `500` on a one- or two-character term as a signal to narrow the search rather than to retry it unchanged. |
