Find and Manage Site Members

Download skillThe skill is a reference md and part of wix-manage skill. You can use the following command to add the full wix-manage skill to your project:
Copy

A site member is a person who signed up to the site and can log in to its members area. Every member is also a contact, but most contacts are not members. To find a person who may not be a member, search contacts instead, as in Find Contacts: POST https://www.wixapis.com/contacts/v5/contacts/search with {"search": {"search": {"expression": "Jane Doe", "mode": "AND"}}}; each result in contacts[] has memberInfo.memberId only when the contact is a member.

All calls go to the Members API. Every request below is complete and was run on a live site: send it as written, with your own values, and do not look up the method schema first. The steps already give each field these calls need: the fieldsets value (FULL), the filter fields and operators (Step 2), the response fields (Step 3), the empty {} body of Approve and Block, and the member.profile.nickname body of Update Member, which needs no id, revision or field mask (Step 4). Reading is safe. Approving, blocking, adding and renaming change the site: Step 4 says when to ask the user first.

Step 1: Always ask for the FULL fieldset

Members calls return the PUBLIC fieldset by default. It has no loginEmail, and it returns status as UNKNOWN. Send "fieldsets": ["FULL"] in a query body, or fieldsets=FULL in a URL, whenever the answer needs the email or the status.

Step 2: Find members

POST https://www.wixapis.com/members/v1/members/query

The user givesQuery Members body
A login email{"query": {"filter": {"loginEmail": "jane@example.com"}}, "fieldsets": ["FULL"]}
A first and last name{"query": {"filter": {"contact.firstName": "Jane", "contact.lastName": "Doe"}}, "fieldsets": ["FULL"]}
A name shown on the site ("Syam K"){"query": {"filter": {"profile.nickname": "Syam K"}}, "fieldsets": ["FULL"]}
A partial name ("syam"){"search": {"expression": "syam", "fields": ["contact.firstName", "contact.lastName", "profile.nickname"]}, "fieldsets": ["FULL"]}
Pending, approved or blocked members{"query": {"filter": {"status": "PENDING"}}, "fieldsets": ["FULL"]}
Members who joined in a period{"query": {"filter": {"$and": [{"createdDate": {"$gte": "2026-10-01T00:00:00Z"}}, {"createdDate": {"$lt": "2026-11-01T00:00:00Z"}}]}}, "fieldsets": ["FULL"]}. One object with both $gte and $lt is rejected with 400
A contact ID{"query": {"filter": {"contactId": "<contact id>"}}, "fieldsets": ["FULL"]}

The filter fields. Query Members filters on these fields, with these operators:

FieldOperators
loginEmail, contact.firstName, contact.lastName, profile.nickname, profile.slug, contactId, id$eq, $in, $startsWith
status (PENDING, APPROVED, BLOCKED, OFFLINE)$eq, $ne, $in
createdDate$gte, $lt, each in its own condition under $and (not in the method schema's list, but it works)

The method schema also lists $exists, but it is rejected with 400 filter parser Unknown operator $exists. A field that is not listed here is rejected with 400 filter parser Unknown token.

Free text (search.fields) accepts loginEmail, contact.firstName, contact.lastName, profile.nickname, profile.slug and profile.title, at most 4 of them.

One member by email or name, with the fallback, as one flow:

  1. Send the filter:

    Copy

    For a name, send {"query": {"filter": {"contact.firstName": "Sam", "contact.lastName": "Ortiz"}}, "fieldsets": ["FULL"]} instead.

    A match comes back as:

    Copy
  2. When members is empty, send the every-member query (below) and keep the member whose loginEmail, contact.firstName and contact.lastName, or profile.nickname equals the user's words, ignoring case. Do both steps before you answer.

  3. Use the member's id for the calls in Step 4.

How these fields behave:

  • In a filter, write each field as one dotted key, exactly as in the table: {"profile.nickname": "Syam K"}. A nested object such as {"profile": {"nickname": "Syam K"}} is rejected with 400 filter parser Unknown token profile.
  • Email and names in a filter match the whole value and ignore case. $startsWith also works on them.
  • Free text searches only profile.nickname unless you send fields, so always send fields. It ignores case and matches the start of a word from 3 letters ("Noe" finds Noel, "No" does not). Any one word is enough: "Syam Nobody" returns Syam Testkumar. So keep only the members whose first name, last name or nickname starts with each word the user gave, ignoring case. For a word shorter than 3 letters, read every member (below) and match in code. Do not search for an email as free text: "jane@example.com" also returns every other member at example.com. Filter on loginEmail instead.
  • New and changed members can be missing from filters and search. Members created or renamed in the last minutes, and in tests up to about 30 minutes, were not found by loginEmail, name or profile.nickname, while a query without a filter returned them at once. So when a filter or a search finds nothing, read every member (below) and match the email or name in code, ignoring case, before you tell the user there is no such member.
  • Sort. Query Members accepts "sorting": [{"fieldName": "createdDate", "order": "DESC"}] inside query (the key is sorting, not sort). List Members rejects a createdDate sort with 400 INVALID_SORT_FIELD.

Every member. Send the query with no filter and page with offset:

Copy

paging.limit is at most 100. metadata.total is the number of members that match; to only count them, send "paging": {"limit": 1} and read metadata.total. Increase offset by limit until you have read metadata.total members. GET https://www.wixapis.com/members/v1/members?fieldsets=FULL&paging.limit=100&paging.offset=0 (List Members) returns the same list.

Step 3: Read the fields

The response holds members[] and metadata (count, offset, total). Each member has:

FieldWhat it holds
idMember ID. Other APIs that work on members take it, for example a blog post's memberId; for a post author, follow Part 0 of How to Create Blog Posts instead
contactIdThe member's contact, for Update a Contact. Do not assume it equals id
loginEmailThe email the member logs in with (FULL or EXTENDED only)
statusPENDING (waiting for approval), APPROVED (approved: can log in once the member has a password), BLOCKED (cannot log in), OFFLINE (a blog guest writer who cannot log in). UNKNOWN means the fieldset was PUBLIC
contact.firstName, contact.lastNameName
profile.nicknameThe name the site shows for the member, such as the author name on blog posts
profile.slugThe member's profile page path
createdDateWhen the member joined
lastLoginDateLast login, when there is one
privacyStatusPRIVATE or PUBLIC profile

Read one member by ID with GET https://www.wixapis.com/members/v1/members/<memberId>?fieldsets=FULL; it returns {"member": {...}}.

Step 4: Change a member

These four calls are complete as shown; send them without a schema lookup. Each returns the changed member in member. Read member.status or member.profile.nickname from the response to confirm; no second read is needed.

A request that names the member and the action ("approve Jane Doe", "block jane@example.com") is the user's confirmation: find the member (Step 2), then make the call. Ask first when the user did not name the action, or when more than one member matches.

Approve a pending member, or unblock a blocked one:

Copy

Block a member (they can no longer log in):

Copy

To unblock, use Approve: on a BLOCKED member it returns the member with status: "APPROVED" (tested on a live site). Both calls succeed when the member already has the target status, so you can repeat them safely.

Change the name the site shows (for example a blog author name):

Copy

The member ID goes in the URL; the body needs no id, revision or field mask. Only the fields you send change; contact.firstName, contact.lastName and loginEmail stay as they were. The response is the whole updated member, with loginEmail and status.

Add a member:

Copy

The new member has status: "APPROVED", and profile.nickname is the contact name unless you send member.profile.nickname. It cannot log in until it sets a password; Send Set Password Email emails it a link, so send that only when the user asks. When adding several members, wait about one second between calls to stay under the rate limit.

Last updated: 4 November 2026

Did this help?