# Get all member consent profiles

`GET /api/members/consent/profiles`

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

HTML version: [Get all member consent profiles](https://support.gladstonesoftware.cloud/reference/members/get-all-member-consent-profiles)

## Overview

Bulk-exports what every member has and has not agreed to: the legal agreements they have signed, the marketing campaigns they have opted into, the data-processing campaigns they have accepted, and the channels they are happy to be contacted on. This is the endpoint to drive a consent-management or CRM sync from — it walks the whole member base rather than one member at a time.

It has **two mutually exclusive modes**:

- **Delta mode** (the default) — returns members whose record was created or modified between `dateFrom` and `dateTo`. Omit both and the window quietly defaults to *the last day only*, so a call with no parameters is not a full export.
- **Full export mode** — set `returnAllRecords=true` and omit both dates. Sending either date alongside it fails with `400`.

Two things about the date filter catch people out. First, it filters on the **member record's** created and modified dates, not on when consent was given — a member whose consent has not changed but whose address has will still appear, and a consent change that does not touch the member record may not. Second, either date being matched is enough: the filter is created-in-range **or** modified-in-range.

Paging runs on member id ascending, using a continuation token; there is no offset. Tokens are mode-specific — one minted in full-export mode is rejected if replayed in delta mode. Keep `returnAllRecords`, `limit` and the dates identical across a sequence. Stop when `continuation-token` comes back as an **empty string**, which is the only end-of-data signal.

One shape quirk: the response is a single object carrying `profiles` and `continuation-token`, not an array, even though the field paths below are written with a leading `[]`.

This is consent data. Anything you cache from it goes stale the moment a member changes their mind, so re-run the delta regularly rather than treating an export as durable.

## Endpoint

`GET {base_url}/api/members/consent/profiles`

`{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 |
|------|------|----------|-------------|
| `dateFrom` | string (date-time) | No | The start of the window, matched against the member record's created and modified dates. ISO 8601. It cannot be in the future. **Defaults to the start of yesterday when omitted** — not to the beginning of time — which is why an unparameterised call returns very little. Cannot be combined with `returnAllRecords=true`. |
| `dateTo` | string (date-time) | No | The end of the window, in the same format. Defaults to now when omitted, and cannot be in the future, so there is no point padding it forward. Cannot be combined with `returnAllRecords=true`. |
| `limit` | integer (int32) | No | How many member profiles to return per page. Valid range is 1 to 100; above 100 is rejected with `400`. `0` or a negative value is not an error — it is silently replaced by the default of 25. Keep it the same across a paging sequence. |
| `continuation-token` | string | No | The cursor for the next page, copied verbatim from the previous response. It carries the last member id seen, and paging resumes at the next member id above it. Do not build one by hand — a malformed token is rejected with `400`. A token minted with `returnAllRecords=true` carries no usable date and is rejected if replayed with `returnAllRecords=false`. Omit it for the first page. Note that the token does **not** carry your date window: you must re-send `dateFrom` and `dateTo` on every page. |
| `returnAllRecords` | boolean | No | Switches from delta mode to a full export of every member. Defaults to `false`. Mutually exclusive with `dateFrom` and `dateTo`. It must stay the same for every call in a paging sequence, because it changes what a continuation token means. |

## Sample request

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

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `[].profiles` | array of object | One page of members, ordered by member id ascending, at most `limit` long. Empty when nothing matched or when you have paged past the end; an empty page always comes with an empty `continuation-token`. Members are included whether or not they have given any consent, so an entry with empty campaign arrays means "asked and declined, or never asked" — not that the member is missing. |
| `[].profiles[].memberId` | integer (int32) | The member this consent profile belongs to, and the cursor paging advances through. Only ids greater than `0` are returned, so the non-member placeholder never appears. |
| `[].profiles[].onlineConsentDate` | string (date-time) | When the member consented to having an online account. `null` when they never have — typically a member who only ever deals with the centre in person. |
| `[].profiles[].onlineConsentGuardianName` | string | The name of the adult who gave online consent on the member's behalf, recorded when the member is below the tenant's age of consent. `null` for an adult member, and also `null` for a junior whose consent was never captured — its presence, not its absence, is the reliable signal. |
| `[].profiles[].privacyPolicySignedDate` | string (date-time) | When the member accepted the privacy policy. `null` if they never have. Read it together with `privacyPolicySigned`, which is the authoritative flag. |
| `[].profiles[].privacyPolicySigned` | boolean | Whether the member has accepted the privacy policy. This is recorded separately rather than derived from the date, so treat it as the answer and the date as supporting detail; they can disagree on older records. |
| `[].profiles[].termsAndConditionsSignedDate` | string (date-time) | When the member signed the operator's terms and conditions, taken from the member's signed agreements. `null` when no terms and conditions agreement is recorded for them. There is no accompanying boolean — `null` is the "not signed" signal. |
| `[].profiles[].healthCommitmentStatementSignedDate` | string (date-time) | When the member signed the health commitment statement — the physical-activity readiness declaration many operators require before use of a gym. `null` when none is recorded. |
| `[].profiles[].modifiedOn` | string (date-time) | When the **member record** was last changed — not when consent last changed. Falls back to the creation date for a member who has never been modified, so it is never `null` for a record that has a creation date. This is one of the two fields the date window filters on. |
| `[].profiles[].createdOn` | string (date-time) | When the member record was created. The other field the date window filters on: a newly created member appears in a delta run even if nothing has been modified since. |
| `[].profiles[].campaignPreferences` | object | The member's opt-ins, split into three lists by the category the operator assigned to each campaign. Always present; its three arrays may each be empty. |
| `[].profiles[].campaignPreferences.marketingCampaigns` | array of object | Campaigns in the `MARKETING` category that the member has opted into — the ones governing whether you may market to them. Only opt-ins appear; a campaign the member has declined is simply absent, so absence means "no consent", not "unknown". |
| `[].profiles[].campaignPreferences.marketingCampaigns[].campaignId` | integer (int32) | The campaign's id, as configured by the operator. Stable within a tenant and different between tenants. This is the id you use when updating the member's campaign consents. |
| `[].profiles[].campaignPreferences.marketingCampaigns[].campaignName` | string | The operator's name for the campaign. Display text and changeable — key on `campaignId`. |
| `[].profiles[].campaignPreferences.marketingCampaigns[].campaignDescription` | string | The longer description the operator wrote for the campaign, usually the wording shown to the member when they opted in. `null` when none was configured. |
| `[].profiles[].campaignPreferences.marketingCampaigns[].captureDate` | string (date-time) | The date the consent was given. Returned as a date with the time truncated to midnight, so do not expect the exact moment of capture. This is your evidence of when consent was obtained. |
| `[].profiles[].campaignPreferences.marketingCampaigns[].expiryDate` | string (date-time) | The date the consent lapses, likewise truncated to midnight. **The platform does not filter expired consents out of this response** — a campaign whose `expiryDate` is in the past is still listed, so compare it against today yourself before treating the member as consented. |
| `[].profiles[].campaignPreferences.marketingCampaigns[].guardianName` | string | The adult who gave this consent on the member's behalf, required when the member is below the age of consent. `null` when the member consented for themselves. |
| `[].profiles[].campaignPreferences.marketingCampaigns[].category` | string | The campaign's category, with spaces stripped. Always `MARKETING` for entries in this array, so it is redundant here — it exists because the same shape is reused across the three lists. |
| `[].profiles[].campaignPreferences.dataCampaigns` | array of object | Campaigns in the `DATA_PROCESSING` category the member has opted into — the lawful-basis consents for processing their data, as distinct from permission to market to them. Same shape as `marketingCampaigns`. |
| `[].profiles[].campaignPreferences.dataCampaigns[].campaignId` | integer (int32) | The data-processing campaign's operator-configured id. |
| `[].profiles[].campaignPreferences.dataCampaigns[].campaignName` | string | The operator's name for the campaign. Display text; key on `campaignId`. |
| `[].profiles[].campaignPreferences.dataCampaigns[].campaignDescription` | string | The operator's longer description, usually the wording the member agreed to. `null` when none was configured. |
| `[].profiles[].campaignPreferences.dataCampaigns[].captureDate` | string (date-time) | When the consent was given, truncated to midnight. |
| `[].profiles[].campaignPreferences.dataCampaigns[].expiryDate` | string (date-time) | When the consent lapses, truncated to midnight. Expired entries are still returned — check the date yourself. |
| `[].profiles[].campaignPreferences.dataCampaigns[].guardianName` | string | The adult who consented on a junior member's behalf. `null` when the member consented for themselves. |
| `[].profiles[].campaignPreferences.dataCampaigns[].category` | string | Always `DATA_PROCESSING` for entries in this array. |
| `[].profiles[].campaignPreferences.communicationTypes` | array of object | The channels the member has agreed to be contacted on — email, SMS and so on, as configured by the operator. A channel that is absent has not been consented to. Note these entries carry no expiry: a channel consent does not lapse on its own. |
| `[].profiles[].campaignPreferences.communicationTypes[].channelId` | string | The channel's code, trimmed of padding. This is the stable identifier to match on; the set of codes is operator-configured. |
| `[].profiles[].campaignPreferences.communicationTypes[].channelName` | string | The operator's display name for the channel, such as `Email`. Changeable — key on `channelId`. |
| `[].profiles[].campaignPreferences.communicationTypes[].captureDate` | string (date-time) | When the member agreed to this channel, truncated to midnight. |
| `[].continuation-token` | string | The cursor to send back as `continuation-token` for the next page. An **empty string** when there is no more data — that, not a short page, is how you know to stop. It encodes the last member id in the page and is only valid for the same `returnAllRecords` mode that produced it. |

## Sample response

```json title="200 OK"
[
  {
    "profiles": [
      {
        "memberId": 12345,
        "onlineConsentDate": "2026-08-14T19:00:00Z",
        "onlineConsentGuardianName": "string",
        "privacyPolicySignedDate": "2026-08-14T19:00:00Z",
        "privacyPolicySigned": true,
        "termsAndConditionsSignedDate": "2026-08-14T19:00:00Z",
        "healthCommitmentStatementSignedDate": "2026-08-14T19:00:00Z",
        "modifiedOn": "2026-08-14T19:00:00Z",
        "createdOn": "2026-08-14T19:00:00Z",
        "campaignPreferences": {
          "marketingCampaigns": [
            {
              "campaignId": 12345,
              "campaignName": "string",
              "campaignDescription": "string",
              "captureDate": "2026-08-14T19:00:00Z",
              "expiryDate": "2026-08-14T19:00:00Z",
              "guardianName": "string",
              "category": "string"
            }
          ],
          "dataCampaigns": [
            {
              "campaignId": 12345,
              "campaignName": "string",
              "campaignDescription": "string",
              "captureDate": "2026-08-14T19:00:00Z",
              "expiryDate": "2026-08-14T19:00:00Z",
              "guardianName": "string",
              "category": "string"
            }
          ],
          "communicationTypes": [
            {
              "channelId": "string",
              "channelName": "string",
              "captureDate": "2026-08-14T19:00:00Z"
            }
          ]
        }
      }
    ],
    "continuation-token": "string"
  }
]
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `returnAllRecords=true` was sent together with `dateFrom` and/or `dateTo`. The body is `You cannot specify a dateFrom and/or dateTo if returnAllRecords is set to true`. |
| `400` | Bad request | `dateFrom` is in the future. The body is `DateFrom {dateFrom} cannot be in the future`. |
| `400` | Bad request | `dateTo` is in the future. The body is `DateTo {dateTo} cannot be in the future`. |
| `400` | Bad request | `dateFrom` or `dateTo` is not a recognisable ISO 8601 date. The body is a validation error rather than one of the messages above. |
| `400` | Bad request | `limit` is greater than 100. The body is `Invalid value supplied for number of profiles per page. Limit must be an integer from 1 to 100.` A limit of `0` or below is not an error — it falls back to 25. |
| `400` | Bad request | A continuation token from full-export mode was replayed with `returnAllRecords=false`. The body is `The continuation-token {token} is not valid while returnAllRecords is false`. |
| `400` | Bad request | The continuation token is malformed — a part that is not a key and value pair, or a value that will not parse. The body names the offending element or value. |
| `500` | Internal server error | An unexpected server-side failure while reading the consent profiles. |
