# List who joined or left a segment on a day

Source: https://kirora.io/docs/api/reference/listSegmentMembershipChanges

`GET /v1/segments/{id}/membership-changes`

Requires an API key with the `contacts:read` scope. [About keys and scopes](https://kirora.io/docs/api/reference/authentication)

Works with integration, agent and partner keys.

The contacts who joined (`change=joined`) or left (`change=left`) the segment on `day`, in the workspace timezone, newest first, from the changes recorded then (kept as long as the workspace's events). `meta.count` is that day's `joinedCount` or `leftCount` from `getSegmentSizeHistory`, on the first page only (null with a `cursor`), so the list and the chart agree.

## Path parameters

- `id` (string, required, uuid) — The segment's id.

## Query parameters

- `limit` (integer, optional, min > 0, max 100, default `20`) — How many items a page holds: 1 to 100, 20 by default.
- `cursor` (string, optional, 1–2,048 characters) — Where the page starts: the previous page's `meta.pagination.nextCursor`. Omit it for the first page, and send the same filters with it.
- `change` (string, required, one of `joined`, `left`) — Who joined (`joined`) or left (`left`) the segment.
- `day` (string, required, date) — The day, `YYYY-MM-DD` in the workspace timezone.

## Header parameters

- `Kirora-Workspace` (string, optional, pattern `^[A-Za-z0-9._:-]{1,128}$`) — Partner keys only: the child workspace to act in, by the external id the partner gave it. Without it, a partner key acts in its own workspace. Any other key that sends it is refused with 403, and an unknown workspace is 404.

## Returns

Returns `200 OK` with a list of `ContactDetail` objects in `data`, and the next page's cursor in `meta` (see [pagination](https://kirora.io/docs/api/reference/pagination)). Otherwise returns an error; [Errors](https://kirora.io/docs/api/reference/errors) lists every code and which to retry.

- `id` (string, required, uuid)
- `externalId` (string | null, required) — Your own id for the contact, if set.
- `email` (string | null, required, email)
- `firstName` (string | null, required)
- `lastName` (string | null, required)
- `phone` (string | null, required) — Phone number in E.164 format.
- `timezone` (string | null, required) — IANA timezone, e.g. `Europe/London`.
- `country` (string | null, required) — ISO 3166-1 alpha-2 code: as written, or inferred from the phone, else the timezone.
- `locale` (string | null, required) — BCP 47 tag (`fr`, `fr-CA`): the language the contact reads (its first subtag), and how merge tags format numbers, dates and money for them.
- `rfm` (object | null, required) — The contact's RFM (recency, frequency and monetary value) group among the workspace's customers, from its purchase events (the workspace's `purchaseEvent`: an order, a paid invoice, a booking, a donation), each score from 1 to 5 (a fifth of the customers each; 5 is the most recent, most frequent or highest spend), and their purchase totals. Spend counts only purchases in the workspace's main currency; when the purchase carries no amount, `monetary` follows frequency. Recomputed daily, so a purchase today shows tomorrow; `null` for someone who has never purchased.
  - `group` (string, required, one of `champions`, `loyal`, `cant_lose_them`, `potential_loyalists`, `new_customers`, `need_attention`, `about_to_sleep`, `at_risk`, `hibernating`, `lost`)
  - `recency` (integer, required, min 1, max 5)
  - `frequency` (integer, required, min 1, max 5)
  - `monetary` (integer, required, min 1, max 5)
  - `purchaseCount` (integer, required, min > 0) — Their purchase events (the workspace's `purchaseEvent`), in any currency.
  - `totalSpent` (object | null, required) — What their purchases' amounts (`purchaseValueProperty`) add up to, in the workspace's main currency (`currency` on `GET /v1/reports/rfm`); purchases in other currencies and refunds are left out. `null` when the purchase carries no amount.
    - `currency` (string | null, required) — The currency, an ISO 4217 code; null when none was named.
    - `value` (number, required) — The amount in that currency.
  - `lastPurchasedAt` (string, required, date-time) — When their latest purchase happened.
- `dates` (map<string, string>, required) — Named calendar dates, e.g. `birthday`, as `YYYY-MM-DD` or `--MM-DD`.
- `attributes` (map<string, object>, required) — Custom attributes, keyed by attribute name.
- `consent` (ContactConsent, required) — Consent on each channel.
  - `email` (boolean, required) — Whether the contact has consented to email.
  - `push` (boolean, required) — Whether the contact has consented to push.
- `createdAt` (string, required, date-time)
- `updatedAt` (string, required, date-time)
- `emailSuppression` (object, required)
  - `suppressed` (boolean, required) — Whether email to this contact is blocked.
  - `reason` (string | null, required) — Why email to this contact is suppressed: `bounced`, `complained`, `complained_transactional`, `unsubscribed`, `manual`, `imported`, or `other_workspace` (a bounce or complaint in another workspace with the same owner or partner).
- `listIds` (string[], required) — Ids of the lists the contact is in.

## Example

```bash
curl 'https://api.kirora.io/v1/segments/018f2a4e-6b1c-7d3e-9f40-37386ae05a6b/membership-changes?change=joined&day=2030-03-14' \
  -H "Authorization: Bearer $KIRORA_API_KEY"
```

Response `200`:

```json
{
  "data": [
    {
      "id": "0192f3a1-7c2e-7d4b-9a10-3e5f6a7b8c9d",
      "externalId": "customer-4821",
      "email": "amaka@example.com",
      "firstName": "Amaka",
      "lastName": "Obi",
      "phone": "+447700900123",
      "timezone": "Europe/London",
      "country": "GB",
      "locale": "en-NG",
      "rfm": {
        "group": "loyal",
        "recency": 3,
        "frequency": 4,
        "monetary": 5,
        "purchaseCount": 6,
        "totalSpent": {
          "currency": "USD",
          "value": 412.5
        },
        "lastPurchasedAt": "2026-03-02T18:20:00.000Z"
      },
      "dates": {
        "birthday": "1992-03-14"
      },
      "attributes": {
        "plan": "pro",
        "favourite_spice": "smoked paprika",
        "orders": 3
      },
      "consent": {
        "email": true,
        "push": false
      },
      "createdAt": "2026-09-12T08:15:00.000Z",
      "updatedAt": "2026-10-01T09:30:00.000Z",
      "emailSuppression": {
        "suppressed": false,
        "reason": null
      },
      "listIds": [
        "0192f3a2-1b3c-7e5d-8a21-4f6a7b8c9d0e"
      ]
    }
  ],
  "meta": {
    "pagination": {
      "limit": 20,
      "nextCursor": null
    },
    "count": 12
  }
}
```
