# Get all promotions

`GET /api/configuration/promotions`

- **Success:** `200 OK`
- **Products:** Operator (`FOH`)
- **Features:** Front of House Generic Access (`FOHGENERIC`)

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

## Overview

Lists the promotions defined for the tenant, each with the promo codes attached to it. A promotion is the campaign — a name, a validity window and an on/off flag; the promo codes are the strings customers actually enter, and one promotion can carry several.

**Nothing is filtered out.** Deactivated promotions, expired promotions and promotions that have not started yet are all returned. There is no `includeInactive` switch here, unlike [Get all promo codes](get-all-promo-codes.md). The only filter available is `promotionType`, and it filters on type, not on state.

The `status` field is your only view of whether a promotion is live, and it is derived — the promotion's active flag itself is not returned. Read the description of `status` before you use it: it is computed from the flag and `validTo` only, it ignores `validFrom` entirely, and a promotion on its final day is reported as `Inactive` rather than `Active`.

The response is a JSON array. There is no paging and no ordering guarantee. An empty result is `200` with `[]` — never `204` and never `404`.

`id` values are allocated per tenant, so they carry no meaning across tenants or environments. Do not hardcode them.

`status` is not recalculated on every request, so a promotion can keep reporting its old status for up to six hours after it crosses its expiry date. Creating, updating or deleting a promotion through this API is reflected immediately; a change made any other way can take up to six hours to appear. Filtering with `promotionType` does not refresh anything.

For a single promotion — including the discounts behind each promo code, which this list omits — call [Get promotion by ID](get-promotion-by-id.md).

## Endpoint

`GET {base_url}/api/configuration/promotions`

`{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 |
|------|------|----------|-------------|
| `promotionType` | string | No | Restricts the list to one kind of promotion. The only accepted values are `Membership` and `Booking`, **matched exactly and case-sensitively** — `membership` or `BOOKING` are rejected with a `400`, they are not normalised. An empty string is also rejected. Omit the parameter to receive every type; there is no default type applied on read. Every promotion has exactly one type, and promotions created without one default to `Membership`, so `?promotionType=Membership` also picks up promotions where the operator never made a choice. |

## Sample request

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

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `[].id` | integer (int32) | The promotion's numeric identifier, assigned by Gladstone on creation. Tenant-local and not meaningful in another tenant or environment. Pass it to [Get promotion by ID](get-promotion-by-id.md) to retrieve the discounts attached to each of its promo codes, which this list does not include. |
| `[].promotionName` | string | The operator's name for the campaign, used to identify it in their own systems. Mandatory and at most 50 characters. Not unique — nothing stops two promotions sharing a name, so match on `id` rather than on this. |
| `[].validFrom` | string (date-time) | The date the promotion is intended to open. The time is truncated to midnight, so the time portion is always zero and should be ignored. Can be `null`, meaning no start date was recorded. **Nothing reads this field on this endpoint** — it is not filtered on, and `status` ignores it completely, so a promotion whose start date is still in the future can be reported as `Active`. If you are deciding what to show a customer, compare this date yourself. |
| `[].validTo` | string (date-time) | The date the promotion is intended to close, truncated to midnight in the same way. `null` means no end date, which `status` treats as never expiring. This is the only date `status` considers, and it is compared against the current UTC date — so a promotion is judged on whole days, not on the moment you call. |
| `[].promoCodes` | array of string | The code strings attached to this promotion. Always an array and never `null`; a promotion with no codes yet returns `[]`. Contains the code text only — no id, window, active flag or discount. To resolve any of those, look the string up with [Get promo code by ID or code](get-promo-code-by-id-or-code.md), wrapping it in curly braces: `/api/configuration/promotion-codes/{SUMMER25}`. Note that each code carries its own `validFrom`, `validTo` and `active` flag, which are independent of the promotion's — a code can be expired inside a promotion that is still `Active`. |
| `[].status` | string (enum) | Derived state — the promotion's active flag itself is never returned, so this is all you get. `Active` means the flag is set and `validTo` is either absent or strictly later than today. `Expired` means the flag is set but `validTo` is strictly earlier than today. `Inactive` covers everything else, and it is doing more work than its name suggests: it is returned both for a promotion the operator has switched off **and**, because the comparisons are strict, for an active promotion whose `validTo` falls on today — the final day of a campaign reports `Inactive`, not `Active`. `validFrom` is not considered at all. The value is not recalculated per request, so it can lag reality by up to six hours. Do not use it as an authority on redeemability; derive that from `validFrom` and `validTo` yourself. |
| `[].promotionType` | string | What the promotion applies to: `Membership` or `Booking`. Never null — it defaults to `Membership`, so a promotion created without an explicit type reports as `Membership` and is indistinguishable from one deliberately set to it. This is the value the `promotionType` query parameter matches against, with the same exact casing. |

## Sample response

```json title="200 OK"
[
  {
    "id": 12345,
    "promotionName": "string",
    "validFrom": "2026-08-14T19:00:00Z",
    "validTo": "2026-08-14T19:00:00Z",
    "promoCodes": [
      "string"
    ],
    "status": "Active",
    "promotionType": "string"
  }
]
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `promotionType` was supplied with a value other than `Membership` or `Booking`. The comparison is case-sensitive and exact, so `membership`, `booking` and an empty string all fail. Body: `Invalid promotionType. Must be either Membership or Booking`. |
| `500` | Internal server error | Any unexpected server-side failure while reading the promotions. The body is empty. Retry; no change to the request avoids it. |
