# Get all price levels

`GET /api/configuration/price-levels`

- **Success:** `200 OK`
- **Products:** Operator (`FOH`), Integrations (`INTEGRATIONS`) (any one of these products, not all)
- **Features:** DataHub (4Global) Integration (`DATAHUB`), Front of House Generic Access (`FOHGENERIC`) (any one of these features, not all)

HTML version: [Get all price levels](https://support.gladstonesoftware.cloud/reference/configuration/get-all-price-levels)

## Overview

Lists the price levels configured for the tenant. A price level is the operator-defined pricing
band a person is charged under — adult, junior, concession, staff and so on. **It carries no money.**
Nothing in this response is an amount; a price level is one half of a lookup, and the actual price
comes from pairing it with a product or activity elsewhere. If you are here looking for prices, this
is not the endpoint.

What a price level does carry is eligibility (`membersAllowed`, `nonMembersAllowed`,
`webNonMembersAllowed`), an age band, and two pointers to other price levels — `nextPriceLevel` for
automatic progression such as a junior ageing into adult pricing, and `infringementPriceLevel` for
the level a member is moved onto when they breach terms, for example falling into debt or missing
payments. The two serve different purposes and are easy to confuse.

Price level ids are **operator-defined and not stable across tenants**. Read them from this call
rather than hardcoding them.

When nothing matches the filter you get `200` with an empty array `[]`, never a `404`, and never
`204 No Content`.

Two things to be aware of before you build against this:

- Price levels have an inactive flag, and **this endpoint does not filter on it**. Price
  levels the operator has retired are returned alongside live ones, and the flag is not in the
  response, so you cannot tell them apart from here.
- `translations` is effectively always empty on this endpoint — see the field description. Use [Get
  price level by ID](get-price-level-by-id.md) when you need localised
  descriptions.

## Endpoint

`GET {base_url}/api/configuration/price-levels`

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

## Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `filter` | string | No | Which eligibility flag to filter on. Accepts `All`, `Member` or `NonMember`, matched case-insensitively and with hyphens stripped, so `non-member`, `NonMember` and `NONMEMBER` are all accepted. `Member` returns price levels where `membersAllowed` is true; `NonMember` returns those where `nonMembersAllowed` is true; `All` applies no eligibility filter. Omitting it, or sending an empty value, is treated as `All`. Anything unrecognised is rejected with `400` — with one exception worth knowing: a bare number is accepted, so `filter=1` behaves as `Member`, `filter=2` as `NonMember`, and any other integer is silently treated as `All` rather than erroring. |
| `webNonMembers` | boolean | No | An extra restriction layered on top of `filter`, not an alternative to it: when `true`, only price levels whose `webNonMembersAllowed` is `true` are returned. Defaults to `false`, which applies no such restriction — it does **not** mean "exclude web non-members". Combine with `filter=NonMember` to get the set a non-member can actually be charged at online. |

## Sample request

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

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `[].id` | string | The price level's identifier, up to 15 characters and unique within the tenant. Operator-defined, so treat it as opaque and never assume a value such as `ADULT` means the same thing at another operator. This is the value you pass as `priceLevelId` to [Get price level by ID](get-price-level-by-id.md), and the value that appears as a member's price level elsewhere in the API. |
| `[].description` | string | The operator's own label for the band, intended for display. Up to 255 characters and never blank: create and update reject an empty description. Do not confuse this limit with the 25-character cap that applies to a price level's *alternative* descriptions, which are a separate per-activity override. |
| `[].ageRangeStart` | integer (int32) | Lower bound in years of the age band this price level covers, used by availability and pricing lookups as the minimum age. Not nullable, so it is always present — `0` means there is no meaningful lower bound rather than "age zero applies". Must be less than or equal to `ageRangeEnd`; that rule is enforced when a price level is created or updated, so you will not see it violated here. |
| `[].ageRangeEnd` | integer (int32) | Upper bound in years of the age band. Not nullable and always present. Read it together with `ageRangeStart` — where the operator uses `nextPriceLevel` for age progression, this is the boundary at which a member moves on. |
| `[].backColourHex` | string | Background colour the operator has assigned for displaying this price level in staff-facing screens, as `#RRGGBB`. An unset colour comes back as an **empty string, not `null`** — test for `""` as well. Purely cosmetic; nothing behavioural depends on it. |
| `[].textColourHex` | string | Foreground colour for the same display, as `#RRGGBB`, with the same empty-string-when-unset behaviour as `backColourHex`. Intended to be legible against `backColourHex`; the platform does not check that it is. |
| `[].membersAllowed` | boolean | Whether members may be charged at this price level. **Only an explicitly enabled flag counts as true** — an unset flag becomes `false`, so a `false` here means "not enabled", which may be because the operator disabled it or because they never set it. This is what `filter=Member` selects on. |
| `[].nonMembersAllowed` | boolean | Whether non-members — casual, pay-as-you-go visitors — may be charged at this price level, with the same "unset becomes `false`" behaviour. This is what `filter=NonMember` selects on. It is independent of `webNonMembersAllowed`: a level can allow non-members at the counter without allowing them online. |
| `[].infringementPriceLevel` | string | The `id` of the price level a member is moved onto when they breach the terms of their membership — for example falling into debt or missing payments. `null` when the operator has configured no infringement level, in which case no automatic move happens. Do not confuse with `nextPriceLevel`; the two exist for entirely different reasons. |
| `[].nextPriceLevel` | string | The `id` of the price level a member progresses to automatically, typically on ageing out of the band defined by `ageRangeStart`/`ageRangeEnd` — junior to adult, for instance. `null` when no progression is configured, meaning the member stays on this level indefinitely. |
| `[].webNonMembersAllowed` | boolean | Whether non-members may be charged at this level through online channels specifically. Defaults to `false`, so it is always present. This is the flag the `webNonMembers=true` query parameter filters on. Treat it as a narrowing of `nonMembersAllowed` rather than a substitute for it. |
| `[].translations` | array of object | Localised alternatives to `description`. **In practice this comes back as an empty array on this endpoint.** It is populated only occasionally, depending on which other requests the tenant has served recently, so you must not depend on it. Call [Get price level by ID](get-price-level-by-id.md) instead when you need localised descriptions. |
| `[].translations[].type` | string | The property the translated `text` replaces — for a price level, the description. |
| `[].translations[].culture` | string | The culture the `text` applies to. No filtering by culture happens server-side, so when the array is populated you receive every configured culture and pick the one you want. |
| `[].translations[].text` | string | The translated description for `culture`. |

## Sample response

```json title="200 OK"
[
  {
    "id": "string",
    "description": "string",
    "ageRangeStart": 1,
    "ageRangeEnd": 1,
    "backColourHex": "string",
    "textColourHex": "string",
    "membersAllowed": true,
    "nonMembersAllowed": true,
    "infringementPriceLevel": "string",
    "nextPriceLevel": "string",
    "webNonMembersAllowed": true,
    "translations": [
      {
        "type": "string",
        "culture": "string",
        "text": "string"
      }
    ]
  }
]
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `filter` was supplied but is not `All`, `Member`, `NonMember` or a bare integer. The response body is empty — there is no message telling you which value was rejected, so check the spelling yourself. |
| `500` | Internal server error | Any unexpected server-side failure. The body is empty and carries no diagnostic detail. |
