<!-- Source: https://developers.memberstack.com/admin-rest-api/member-actions -->
<!-- Markdown version of a Memberstack developer documentation page. Canonical HTML: https://developers.memberstack.com/admin-rest-api/member-actions -->

# Member Actions

The Memberstack Admin REST API provides powerful endpoints for member management. This guide covers all member-related operations including listing, retrieving, creating, updating, and deleting members.

Before You Start

-   Make sure you have your secret key ready (refer to the [Quick Start](/admin-rest-api/quick-start) guide for authentication details)
-   All examples assume you've set up proper authentication headers
-   Be mindful of the rate limit (25 requests per second)

## List Members

Retrieve a paginated list of all members in your application.

### Endpoint

```plaintext
GET https://admin.memberstack.com/members
```

### URL Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| after | number | The endCursor after which the querying should start |
| order | string | The order in which members should be queried (ASC or DESC, default: ASC) |
| first | number | Alias for `limit`. If both are supplied, `first` takes precedence (same default of 50 and max of 100). |
| limit | number | The maximum number of members to return (default: 50, max: 100; values above 100 are capped at 100) |
| includeJSON | string | Set to `"true"` to include each member's `json` field in the response. Omitted by default for performance. |

### Examples

Using curl:

```bash
curl --location --request GET 'https://admin.memberstack.com/members' \
--header 'x-api-key: sk_sb_your_secret_key'
```

Using Axios:

```javascript
const axios = require('axios');

const API_KEY = process.env.MEMBERSTACK_SECRET_KEY;
const BASE_URL = 'https://admin.memberstack.com/members';
const headers = { "X-API-KEY": API_KEY };

// Basic request
const response = await axios.get(BASE_URL, { headers });

// With pagination
const paginatedResponse = await axios.get(BASE_URL, { 
  headers,
  params: {
    limit: 10,
    after: 123456,
    order: 'DESC'
  }
});
```

### Response

```json
{
  "totalCount": 25,      // Total number of members
  "endCursor": 456,      // Cursor for pagination
  "hasNextPage": true,   // Whether more results exist
  "data": [              // Array of member objects
    {
      "id": "mem_abc123",
      "createdAt": "2022-05-19T18:57:35.143Z",
      "lastLogin": "2022-05-19T18:57:35.143Z",
      "auth": {
        "email": "john@example.com"
      },
      "verified": true,
      "customFields": {
        "country": "Germany"
      },
      "metaData": {
        "avatar": "photo.png"
      },
      "loginRedirect": "/welcome",
      "stripeCustomerId": null,
      "profileImage": null,
      "permissions": ["view:basic:workouts"],
      "planConnections": [
        {
          "id": "con_xyz789",
          "active": true,
          "status": "ACTIVE",
          "planId": "pln_123abc",
          "planName": "Basic",
          "type": "FREE",
          "payment": null
        }
      ]
    },
    // Additional members...
  ]
}
```

> 💡 **Tip:**
>
> Tips for working with pagination:
>
> -   Use the `endCursor` value from the response as the `after` parameter in your next request
> -   Check `hasNextPage` to determine if more results are available
> -   Set appropriate `limit` values to balance request count and payload size

## Get Member

Retrieve a specific member by ID or email.

### Endpoint

```plaintext
GET https://admin.memberstack.com/members/:id_or_email
```

#### URL Parameters

Replace `:id_or_email` with either:

-   Member ID (starts with "mem\_")
-   Member email address (URL-encoded)

### Query Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| include | string | Comma-separated list of optional relations to embed on the response. Currently the only recognized value is `teams` (lowercase, exact match). Whitespace and duplicates are tolerated; unknown values are silently ignored. Omit the parameter to receive the default member shape. |

### Examples

Get member by ID:

```bash
curl --location --request GET 'https://admin.memberstack.com/members/mem_abc123' \
--header 'x-api-key: sk_sb_your_secret_key'
```

Get member by email:

```bash
// Remember to URL-encode the email address
curl --location --request GET 'https://admin.memberstack.com/members/example%40test.com' \
--header 'x-api-key: sk_sb_your_secret_key'
```

Get member with team memberships:

```bash
curl --location --request GET 'https://admin.memberstack.com/members/mem_abc123?include=teams' \
--header 'x-api-key: sk_sb_your_secret_key'
```

Using Axios:

```javascript
const axios = require('axios');

const API_KEY = process.env.MEMBERSTACK_SECRET_KEY;
const BASE_URL = 'https://admin.memberstack.com/members';
const headers = { "X-API-KEY": API_KEY };

// Get by ID
const member = await axios.get(`${BASE_URL}/mem_abc123`, { headers });

// Get by email (URL-encode the email)
const encodedEmail = encodeURIComponent('user@example.com');
const memberByEmail = await axios.get(`${BASE_URL}/${encodedEmail}`, { headers });

// Get with team memberships embedded
const withTeams = await axios.get(`${BASE_URL}/mem_abc123`, {
  headers,
  params: { include: 'teams' }
});
```

### Response

```json
{
  "data": {
    "id": "mem_abc123",
    "auth": {
      "email": "user@example.com"
    },
    "createdAt": "2022-05-19T18:57:35.143Z",
    "lastLogin": "2022-05-19T18:57:35.143Z",
    "verified": true,
    "metaData": {
      "language": "English"
    },
    "customFields": {
      "country": "United States",
      "firstName": "John"
    },
    "permissions": ["view:content"],
    "loginRedirect": "/dashboard",
    "stripeCustomerId": null,
    "profileImage": null,
    "json": {},
    "planConnections": [
      {
        "id": "con_xyz789",
        "active": true,
        "status": "ACTIVE",
        "planId": "pln_123abc",
        "planName": "Basic",
        "type": "FREE",
        "payment": null
      }
    ]
  }
}
```

**Not found:** if no member matches the given ID or email, this endpoint still returns `200` with `"data": null` — it does not return a `404`. Check for a `null` `data` value to detect a missing member.

### Including Team Memberships

Append `?include=teams` to embed the member's team memberships on the response. The endpoint remains fully backwards-compatible: when the parameter is omitted, the response is byte-identical to the default shape above and no `teams` field is added.

| Field | Type | Description |
| --- | --- | --- |
| id | string | The team's unique identifier. |
| role | string | This member's role on the team — `"OWNER"` or `"MEMBER"`. |
| createdAt | string | ISO timestamp of when the team was created. |
| inviteToken | string | The team's invite token. The Admin API always returns this regardless of the member's role, so you can construct invite links server-side. |
| currentTeamMemberCount | number | Live count of members currently on the team. |
| maxTeamMembers | number \| null | Seat cap from the team's owner plan price. `null` if no paid team plan is attached. |
| plan | object \| null | The team's owner plan (`id`, `name`, `teamAccountInviteSignupLink`, `teamAccountUpgradeLink`). When a signup/upgrade link is configured, it is normalized to begin with `/`; when it is not configured, the field is returned as an empty string (`""`). The whole `plan` object is `null` when the team has no active owner plan connection. |

Example response with `?include=teams`:

```json
{
  "data": {
    "id": "mem_abc123",
    "auth": {
      "email": "user@example.com"
    },
    "createdAt": "2022-05-19T18:57:35.143Z",
    "lastLogin": "2022-05-19T18:57:35.143Z",
    "metaData": {},
    "customFields": {},
    "permissions": ["view:content"],
    "loginRedirect": "/dashboard",
    "planConnections": [ /* ...unchanged... */ ],
    "teams": [
      {
        "id": "cln4abc123xyz0000abcd",
        "role": "OWNER",
        "createdAt": "2026-05-01T18:57:35.143Z",
        "inviteToken": "abc123def456",
        "currentTeamMemberCount": 3,
        "maxTeamMembers": 3,
        "plan": {
          "id": "pln_team123",
          "name": "3 Mates",
          "teamAccountInviteSignupLink": "/team-signup",
          "teamAccountUpgradeLink": "/team-upgrade"
        }
      }
    ]
  }
}
```

> 💡 **Tip:**
>
> Notes on `include=teams`:
>
> -   The response includes one entry per team the member belongs to. Members on multiple teams get multiple entries.
> -   If the member has no team affiliations, `teams` is an empty array (`[]`).
> -   The value must be exactly `teams` (lowercase). Substring or case variants such as `team` or `TEAMS` will not activate the include.
> -   Unknown `include` values are silently ignored — e.g. `?include=teams,foo` still returns teams.
> -   Omitting the parameter preserves the existing response shape exactly, so adding `include=teams` is a safe, opt-in change.

## Create Member

Create a new member in your application.

### Endpoint

```plaintext
POST https://admin.memberstack.com/members
```

### Request Body

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| email | string | Yes | The member's email address |
| password | string | Conditional | The member's password. Required unless your app has passwordless (email/OTP) authentication enabled, in which case it may be omitted. |
| plans | array | No | Array of plan objects: `[{'planId': 'pln_abc'}]` |
| customFields | object | No | Custom fields for the member |
| metaData | object | No | Metadata for the member |
| json | object | No | JSON data for the member |
| loginRedirect | string | No | URL to redirect to after login |

### Examples

Using curl:

```bash
curl --location --request POST 'https://admin.memberstack.com/members' \
--header 'x-api-key: sk_sb_your_secret_key' \
--header 'Content-Type: application/json' \
--data-raw '{
  "email": "john@example.com",
  "password": "securePassword123",
  "plans": [
    {
      "planId": "pln_abc123"
    }
  ],
  "customFields": {
    "firstName": "John",
    "lastName": "Doe",
    "country": "USA"
  },
  "metaData": {
    "source": "API"
  },
  "json": {
    "preferences": {
      "theme": "dark",
      "notifications": true
    }
  },
  "loginRedirect": "/dashboard"
}'
```

Using Axios:

```javascript
const axios = require('axios');

const API_KEY = process.env.MEMBERSTACK_SECRET_KEY;
const BASE_URL = 'https://admin.memberstack.com/members';
const headers = { 
  "X-API-KEY": API_KEY,
  "Content-Type": "application/json"
};

const data = {
  email: "john@example.com",
  password: "securePassword123",
  plans: [
    {
      planId: "pln_abc123"
    }
  ],
  customFields: {
    firstName: "John",
    lastName: "Doe",
    country: "USA"
  },
  metaData: {
    source: "API"
  },
  json: {
    preferences: {
      theme: "dark",
      notifications: true
    }
  },
  loginRedirect: "/dashboard"
};

const response = await axios.post(BASE_URL, data, { headers });
```

### Response

```json
{
  "data": {
    "id": "mem_new123",
    "auth": {
      "email": "john@example.com"
    },
    "createdAt": "2023-01-19T12:34:56.789Z",
    "lastLogin": null,
    "verified": false,
    "metaData": {
      "source": "API"
    },
    "customFields": {
      "firstName": "John",
      "lastName": "Doe",
      "country": "USA"
    },
    "json": {
      "preferences": {
        "theme": "dark",
        "notifications": true
      }
    },
    "permissions": [],
    "loginRedirect": "/dashboard",
    "stripeCustomerId": null,
    "profileImage": null,
    "planConnections": [
      {
        "id": "con_new456",
        "active": true,
        "status": "ACTIVE",
        "planId": "pln_abc123",
        "planName": "Pro",
        "type": "FREE",
        "payment": null
      }
    ]
  }
}
```

> ⚠️ **Important:**
>
> Important notes when creating members:
>
> -   The `plans` array is only for free plans (those with IDs starting with `pln_`)
> -   For paid plans, members need to go through the Stripe checkout flow using the DOM package
> -   Passwords should be secure and meet your organization's requirements
> -   Email addresses must be unique within your Memberstack application

## Update Member

Update an existing member's information.

### Endpoint

```plaintext
PATCH https://admin.memberstack.com/members/:id
```

#### URL Parameters

Replace `:id` with the member's ID (starts with "mem\_")

### Request Body

You can update any of the following fields:

| Parameter | Type | Description |
| --- | --- | --- |
| email | string | Update the member's email address |
| customFields | object | Update custom fields |
| metaData | object | Update metadata |
| json | object | Update JSON data |
| loginRedirect | string | Update login redirect URL |
| verified | boolean | Set the member's email-verified status (true or false) |
| profileImage | string | URL of the member's profile image |

### Examples

Using curl:

```bash
curl --location --request PATCH 'https://admin.memberstack.com/members/mem_abc123' \
--header 'x-api-key: sk_sb_your_secret_key' \
--header 'Content-Type: application/json' \
--data-raw '{
  "customFields": {
    "firstName": "John",
    "lastName": "Updated",
    "country": "Canada"
  },
  "email": "john.updated@example.com",
  "metaData": {
    "lastUpdated": "2023-01-20"
  }
}'
```

Using Axios:

```javascript
const axios = require('axios');

const API_KEY = process.env.MEMBERSTACK_SECRET_KEY;
const BASE_URL = 'https://admin.memberstack.com/members';
const headers = { 
  "X-API-KEY": API_KEY,
  "Content-Type": "application/json"
};

const data = {
  customFields: {
    firstName: "John",
    lastName: "Updated",
    country: "Canada"
  },
  email: "john.updated@example.com",
  metaData: {
    lastUpdated: "2023-01-20"
  }
};

const response = await axios.patch(`${BASE_URL}/mem_abc123`, data, { headers });
```

### Response

```json
{
  "data": {
    "id": "mem_abc123",
    "auth": {
      "email": "john.updated@example.com"
    },
    "createdAt": "2022-05-19T18:57:35.143Z",
    "lastLogin": "2022-05-19T18:57:35.143Z",
    "verified": true,
    "metaData": {
      "lastUpdated": "2023-01-20"
    },
    "customFields": {
      "firstName": "John",
      "lastName": "Updated",
      "country": "Canada"
    },
    "permissions": ["view:content"],
    "loginRedirect": "/dashboard",
    "stripeCustomerId": null,
    "profileImage": null,
    "json": {},
    "planConnections": [
      {
        "id": "con_xyz789",
        "active": true,
        "status": "ACTIVE",
        "planId": "pln_123abc",
        "planName": "Basic",
        "type": "FREE",
        "payment": null
      }
    ]
  }
}
```

> 💡 **Tip:**
>
> Tips when updating members:
>
> -   Updates are partial - you only need to include the fields you want to change
> -   `customFields` and `metaData` are **shallow-merged** with the member's existing values: keys you include are added or overwritten, and keys you omit are preserved. (`metaData` additionally drops any key whose value is falsy.)
> -   `json` is the exception — it is **fully replaced** with the object you send.
> -   To change a single key in `customFields` or `metaData` you can send just that key; you do not need to re-send the whole object.
> -   If the member does not exist, the request returns `400` with the message `"There is no member with this identifier."` (code `generic-message`).

## Delete Member

Permanently remove a member from your application.

### Endpoint

```plaintext
DELETE https://admin.memberstack.com/members/:id
```

#### URL Parameters

Replace `:id` with the member's ID (starts with "mem\_")

### Request Body (Optional)

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| deleteStripeCustomer | boolean | false | Delete the associated Stripe customer |
| cancelStripeSubscriptions | boolean | false | Cancel the associated Stripe subscriptions |

### Examples

Basic deletion with curl:

```bash
curl --location --request DELETE 'https://admin.memberstack.com/members/mem_abc123' \
--header 'x-api-key: sk_sb_your_secret_key'
```

Advanced deletion with curl:

```bash
curl --location --request DELETE 'https://admin.memberstack.com/members/mem_abc123' \
--header 'x-api-key: sk_sb_your_secret_key' \
--header 'Content-Type: application/json' \
--data-raw '{
  "deleteStripeCustomer": true,
  "cancelStripeSubscriptions": true
}'
```

Using Axios:

```javascript
const axios = require('axios');

const API_KEY = process.env.MEMBERSTACK_SECRET_KEY;
const BASE_URL = 'https://admin.memberstack.com/members';
const headers = { 
  "X-API-KEY": API_KEY,
  "Content-Type": "application/json"
};

// Basic deletion
const response = await axios.delete(`${BASE_URL}/mem_abc123`, { headers });

// Advanced deletion
const advancedResponse = await axios.delete(`${BASE_URL}/mem_abc123`, { 
  headers,
  data: {
    deleteStripeCustomer: true,
    cancelStripeSubscriptions: true
  }
});
```

### Response

```json
{
  "data": {
    "id": "mem_abc123"
  }
}
```

> ⚠️ **Important:**
>
> **Warning:** Deleting a member is permanent and cannot be undone.
>
> -   Consider implementing a soft-delete mechanism in your application if you need to preserve member data
> -   Use the `deleteStripeCustomer` and `cancelStripeSubscriptions` options carefully
> -   Make sure to handle any dependent resources in your own database
> -   If the member does not exist (or belongs to another app), the request returns `400` with the message `"There is no member with this identifier."` (code `generic-message`).

## Plan Management

Add and remove free plans from members.

### Add a Free Plan

Add a free plan to an existing member:

```plaintext
POST https://admin.memberstack.com/members/:id/add-plan
```

#### URL Parameters

Replace `:id` with the member's ID (starts with "mem\_")

### Request Body

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| planId | string | Yes | The ID of the free plan to add (starts with "pln\_") |

### Examples

Using curl:

```bash
curl --location --request POST 'https://admin.memberstack.com/members/mem_abc123/add-plan' \
--header 'x-api-key: sk_sb_your_secret_key' \
--header 'Content-Type: application/json' \
--data-raw '{
  "planId": "pln_free123"
}'
```

Using Axios:

```javascript
const axios = require('axios');

const API_KEY = process.env.MEMBERSTACK_SECRET_KEY;
const BASE_URL = 'https://admin.memberstack.com/members';
const headers = { 
  "X-API-KEY": API_KEY,
  "Content-Type": "application/json"
};

const data = {
  planId: "pln_free123"
};

const response = await axios.post(`${BASE_URL}/mem_abc123/add-plan`, data, { headers });
```

### Response

A successful request returns a 200 status code with no response body.

### Remove a Free Plan

Remove a free plan from an existing member:

```plaintext
POST https://admin.memberstack.com/members/:id/remove-plan
```

#### URL Parameters

Replace `:id` with the member's ID (starts with "mem\_")

### Request Body

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| planId | string | Yes | The ID of the free plan to remove (starts with "pln\_") |

### Examples

Using curl:

```bash
curl --location --request POST 'https://admin.memberstack.com/members/mem_abc123/remove-plan' \
--header 'x-api-key: sk_sb_your_secret_key' \
--header 'Content-Type: application/json' \
--data-raw '{
  "planId": "pln_free123"
}'
```

Using Axios:

```javascript
const axios = require('axios');

const API_KEY = process.env.MEMBERSTACK_SECRET_KEY;
const BASE_URL = 'https://admin.memberstack.com/members';
const headers = { 
  "X-API-KEY": API_KEY,
  "Content-Type": "application/json"
};

const data = {
  planId: "pln_free123"
};

const response = await axios.post(`${BASE_URL}/mem_abc123/remove-plan`, data, { headers });
```

### Response

A successful request returns a 200 status code with no response body.

> ⚠️ **Important:**
>
> Important notes about plan management:
>
> -   These endpoints only work with free plans (plan IDs starting with `pln_`)
> -   For paid plans, use the DOM package's checkout flow or Stripe Customer Portal
> -   Removing a plan immediately revokes the member's access to that plan's features
> -   A member can have multiple plans simultaneously
