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.
- Make sure you have your secret key ready (refer to the 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.
Retrieve a paginated list of all members in your application.
limit. If both are supplied, first takes precedence (same default of 50 and max of 100)."true" to include each member's json field in the response. Omitted by default for performance.curl --location --request GET 'https://admin.memberstack.com/members' \
--header 'x-api-key: sk_sb_your_secret_key'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'
}
});{
"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...
]
}- Use the
endCursorvalue from the response as theafterparameter in your next request - Check
hasNextPageto determine if more results are available - Set appropriate
limitvalues to balance request count and payload size
Get Member
Retrieve a specific member by ID or email.
Retrieve a specific member by ID or email. Replace :id_or_email with either a Member ID (starts with "mem_") or a member email address (URL-encoded).
teams (lowercase, exact match). Whitespace and duplicates are tolerated; unknown values are silently ignored. Omit the parameter to receive the default member shape.curl --location --request GET 'https://admin.memberstack.com/members/mem_abc123' \
--header 'x-api-key: sk_sb_your_secret_key'// 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'curl --location --request GET 'https://admin.memberstack.com/members/mem_abc123?include=teams' \
--header 'x-api-key: sk_sb_your_secret_key'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' }
});{
"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. |
{
"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"
}
}
]
}
}- 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,
teamsis an empty array ([]). - The value must be exactly
teams(lowercase). Substring or case variants such asteamorTEAMSwill not activate the include. - Unknown
includevalues are silently ignored, e.g.?include=teams,foostill returns teams. - Omitting the parameter preserves the existing response shape exactly, so adding
include=teamsis a safe, opt-in change.
Create Member
Create a new member in your application.
Create a new member in your application.
[{'planId': 'pln_abc'}].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"
}'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 });{
"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
}
]
}
}- The
plansarray is only for free plans (those with IDs starting withpln_) - 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.
Update an existing member's information. Replace :id with the member's ID (starts with "mem_"). You can update any of the fields below.
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"
}
}'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 });{
"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
}
]
}
}- Updates are partial - you only need to include the fields you want to change
customFieldsandmetaDataare shallow-merged with the member's existing values: keys you include are added or overwritten, and keys you omit are preserved. (metaDataadditionally drops any key whose value is falsy.)jsonis the exception, it is fully replaced with the object you send.- To change a single key in
customFieldsormetaDatayou can send just that key; you do not need to re-send the whole object. - If the member does not exist, the request returns
400with the message"There is no member with this identifier."(codegeneric-message).
Delete Member
Permanently remove a member from your application.
Permanently remove a member from your application. Replace :id with the member's ID (starts with "mem_"). The request body is optional.
false.false.curl --location --request DELETE 'https://admin.memberstack.com/members/mem_abc123' \
--header 'x-api-key: sk_sb_your_secret_key'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
}'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
}
});{
"data": {
"id": "mem_abc123"
}
}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
deleteStripeCustomerandcancelStripeSubscriptionsoptions 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
400with the message"There is no member with this identifier."(codegeneric-message).
Plan Management
Add and remove free plans from members.
Add a Free Plan
Add a free plan to an existing member:
Add a free plan to an existing member. Replace :id with the member's ID (starts with "mem_").
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"
}'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 });Remove a Free Plan
Remove a free plan from an existing member:
Remove a free plan from an existing member. Replace :id with the member's ID (starts with "mem_").
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"
}'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 });- 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