For Admins12 min read

Importing Members

When you need to add many people at once, the CSV import tool and the REST Sync API are far more efficient than adding them one by one. This article covers both.

Before anything else, it is worth being clear about what an import is for, because this is the single most common misunderstanding:

A CSV import never emails anyone, and it never uses a seat. It stages roster records. Sending invitations is a separate, deliberate action you take afterwards from the Members page, and that is the step that consumes seats. If you are looking for the fastest way to get people into their accounts, you need both halves: import to stage the roster, then Bulk Invite to email them.

The Sync API behaves the same way by default, with one exception you can turn on deliberately, covered under the API section below.

CSV import page showing the Upload CSV Roster card, the file drop area, the Full Roster Sync checkbox, and the Import History table below

Screenshot placeholder

CSV Import

Preparing Your File

MentorNeko reads exactly three pieces of information from a CSV. Anything else in the file is ignored, so you can upload an export from your membership system without stripping the extra columns out first.

| Column | Also accepted as | Required | What it does | |---|---|---|---| | email | email address | Yes | The member's email address. Used to match them to an existing record, and later to send their invitation. | | name | full name | Yes | The member's full name, in a single column. | | orgMemberId | member id, org_member_id | Recommended | Your internal HR or membership system ID. |

Column headers are matched case-insensitively, with quotes and surrounding spaces stripped, so Email, EMAIL and "email" all work. A template is available from the import page via Download CSV template, and it is the authoritative example:

| email | name | orgMemberId | |---|---|---| | jane.doe@company.com | Jane Doe | EMP-001 | | john.smith@company.com | John Smith | EMP-002 | | alex.chen@company.com | Alex Chen | EMP-003 |

A few practical points:

  • Both email and name are required for a row to create or update anybody. A row that has an email but no name is not an error. It is skipped quietly, which is exactly why this catches people out (see below).
  • Separate first name and last name columns are not read. MentorNeko stores a single name. If your export has firstName and lastName, combine them into one name column before uploading.
  • A role column is not read. Whether someone wants to mentor, be mentored or just network is a choice each member makes when they set up their profile, and they can change it later. It is an expression of interest rather than a property of the roster, so an import never sets or clears it. A role column in your file is ignored rather than rejected, so an existing export still uploads cleanly.
  • membershipExpiry is not read from a CSV. It exists only on the Sync API path described later in this article.
  • Maximum file size is 10 MB. An additive import can be split across several files safely. A Full Roster Sync cannot: each file claims to be your complete roster, so splitting one tells MentorNeko that everyone in the other files is missing. If a full roster will not fit, remove columns MentorNeko does not read (it only needs three) before splitting the change, and contact support if it still will not fit.

If Your Column Headers Are Wrong

This is the failure worth planning around, because it does not look like a failure.

If your file uses headers MentorNeko does not read (First Name and Last Name instead of name, for example), every row still carries an email, so every row is still recognised as a person on the roster. But no row has a usable name, so none of them can be written. The import finishes, adds nobody, and reports its status as Partial rather than an error.

If an import reports zero members created when you expected hundreds, check your header row first. It is almost always this.

Three row-level conditions are reported as genuine errors, each listed individually in Import History with its row number:

  • the row has neither an email nor a member ID, so nothing in it can identify a person;
  • the row's member ID and email point at two different existing members, so applying it would move one person's email onto another's record;
  • the row's identifier matches two existing members once normalized, so there is no way to tell which one it means.

The last two usually mean two records need merging in your source system. MentorNeko skips those rows rather than guessing.

BANNED members are always skipped, even if they appear in the file, and no error is raised for them.

Uploading

  1. Go to Admin > Members > Import.
  2. Select your CSV in the upload area.
  3. Decide whether this file is your complete roster (see the next section).
  4. Click Start Import, or Preview Changes if you ticked Full Roster Sync.
  5. When you are ready for these people to have access, go to Admin > Members and run Bulk Invite.

The file uploads to secure cloud storage and is processed in the background, so large rosters continue reliably after you navigate away.

Step 5 is the one people miss, because importing puts people on the roster without inviting them. It is genuinely optional, though: skip it if you are staging a roster ahead of a launch, or if this import only updated details for people who already have accounts. The import itself sends no email and allocates no seats. That makes it useful for staging who you plan to contact, but it does not block members from requesting access themselves, as explained below.

If you are used to an earlier version of MentorNeko that offered a "Send Invitations" option during import, that control is gone. Bulk Invite replaces it.

What Status Imported Members End Up In

No row an import writes consumes a seat.

  • New people are created as Provisioned, which the roster displays as Not emailed. They are on your roster, MentorNeko has not contacted them, and they do not count against your seat limit.
  • People who were Inactive and reappear on the file come back the same way, as Provisioned and unseated.
  • Everybody else keeps the status they already have. An import will not move an Active member backwards.

Those two names are the same thing. The status is called Provisioned, and the Members roster labels it Not emailed, which is also the name of the first Bulk Invite audience. All the statuses and their roster labels are listed in Managing Members.

One thing to be clear about before you stage a roster: Not emailed is a roster stage, not a complete delivery history or an access block. A new import has not been contacted, but a returning member reactivated to Provisioned may have received email during an earlier membership stint. Either can go to your login page, request a magic link, become Active, and consume a seat without waiting for Bulk Invite. That is usually harmless, since they have to know the address and go looking. But if a group genuinely must not get in yet, keep them off the roster until you are ready rather than relying on Provisioned to hold them back.

To actually get people into their accounts, use Bulk Invite on the Members page afterwards. That is where seats are allocated and where email is sent. See Managing Members for the audiences it offers.

One limitation to plan around: Bulk Invite only lists people who have not finished setting up their profile, because there is nothing to invite someone to once they have. So a member who completed their profile, was later deactivated, and now returns on a roster file is re-activated quietly and will not appear in any bulk audience. Nothing will contact them automatically. Reach those people with the single Add Member action on the Members page, or simply tell them their account is live again. The import review screen states this on-screen as well.

Full Roster Sync

Ticking Full Roster Sync tells MentorNeko that the file is your complete active roster, which means members missing from it should be deactivated. Deactivation is not a quiet bookkeeping change: it ends the member's active matches and cancels their mentoring circles, and the people affected are notified.

A sync only ever deactivates members it currently manages. Every member record carries a note of which source is responsible for it: CSV import, the Sync API, or manual admin action. A CSV Full Roster Sync only considers the members CSV import manages, and a Sync API full sync only considers the ones the API manages.

The important part is that this is current ownership, and it changes hands. An import takes over any record it actually updates. Ownership follows the file, not the original creation.

That gives two rules, and they are opposite sides of the same coin:

  • A member your file has never named is not yours to deactivate. Someone added by hand, or who signed themselves up through an approved domain, stays under manual management and is skipped by every sync, however many times you run one. If such a member has left, deactivate them from the Members page. Your export never has to know they exist.
  • A member your file has named once is governed by it from then on, unless an admin takes them back. The import that included them took ownership, so a later file that omits them can deactivate them. If you add someone by hand and they also appear in your export, they now belong to the sync, and leaving them off a future file will remove them. See the hand-back rule below.

The practical version: decide per person whether the roster file or an admin manages them, and be consistent. Trouble comes from a member who is in the export sometimes.

Ownership can be handed back. Choosing Set Active on a member from the Members page returns them to manual management, and so does Reinstate Member for a banned member, because both set the member Active. Deactivating does not. A member handed back this way is out of the sync's reach again until the next file that names them.

Because of that, a Full Roster Sync is a two-stage operation. Nothing is written until you have seen the consequences and confirmed them.

There is also a ceiling on how much one sync may remove: 100 people at most, and normally no more than 20% of the members that source manages, except that removing fewer than three people is always allowed. If you are planning a large off-boarding, read "The Deactivation Limit" below before you prepare the file, because you will need to do it in phases.

Full Roster Sync review screen showing New members, Updated, Skipped and Errors counts above a named list of members missing from the file, with Discard and confirm buttons

Screenshot placeholder

Stage one: preview. Click Preview Changes. MentorNeko works out exactly what applying the file would do without touching your roster, and the page updates itself while it works. The preview has its own address, so you can reload the page, open it in another tab, or send the link to a colleague. Previews are valid for 24 hours.

Stage two: review and confirm. The review screen shows:

  • counts of New members, Updated, Skipped and Errors;
  • whether anyone would be deactivated and, if so, who they are by name, with how many active matches and circles each one would take down;
  • a paginated list when there are more than a screenful.

You then either Discard the preview or confirm it. The confirmation dialog repeats the exact numbers rather than asking a generic "are you sure": a destructive sync names how many people it deactivates in the dialog title, its body, and the final button, so you have to read the count twice before it happens.

When a Confirmation Is Refused

A preview authorises one specific list of people. Between reviewing it and confirming it, your roster keeps moving: someone signs up, an admin deactivates somebody, a draft circle goes live. MentorNeko therefore re-checks everything at confirm time, and it will only ever act on fewer people than you reviewed, never more.

It refuses outright if the uploaded file has changed, if anybody new would be added to the deactivation list, or if a circle you reviewed as a draft has since gone live (cancelling a live circle emails its participants, which is not what you were shown).

Refusal does not always mean nothing happened, and the difference is visible in Import History. There are two moments where it can happen:

| Import History status | What it means | |---|---| | Failed | The whole import was declined before anything was written. Your roster is untouched. Generate a fresh preview and review it again. | | Partial | The additive half already landed, so new members were created and existing ones updated, but nobody was deactivated because the reviewed list changed while the import was running. The people you expected to be deactivated are still active. |

If you see Partial after a Full Roster Sync, do not assume the run was a no-op. Re-run the sync once your roster has settled.

Separately, if somebody on the reviewed list is simply no longer deactivatable (an admin already deactivated them, or a record correction means the file now names them after all), they are quietly skipped rather than forced, and the import note tells you how many.

The Deactivation Limit

MentorNeko refuses to deactivate an implausibly large share of your roster in one go.

If a sync would deactivate more than 20% of the members that import source currently keeps live (those shown as Not emailed, Invited, Setup unfinished or Active), or more than 100 people outright, the deactivation half is declined. The additive half still applies: everyone in the file is created or updated as normal, and nobody is deactivated. Small changes are exempt from the percentage rule, so a sync deactivating fewer than three people is never blocked by it, though the 100-person ceiling always applies.

The preview tells you this up front. The review screen still lists the members missing from the file, under a heading stating plainly that nobody will be deactivated.

There is no override. A genuinely large off-boarding has to be done in phases, and it is worth being precise about what that means, because it is not the same as splitting your roster into smaller files. Every file you upload with Full Roster Sync ticked must still be your complete roster. What changes between phases is how many departures each file leaves out.

So to remove 250 people, you might upload a complete roster that still includes 150 of them and omits the first 100, let that apply, then upload a complete roster omitting the next batch, and so on. Each file is whole. Each one deactivates only the batch it leaves out, and the people held back stay active until their phase.

Splitting the roster itself into partial files would deactivate everyone the file happens not to contain, which is the mistake this limit usually catches. The limit is deliberate: the overwhelming majority of oversized sweeps are a truncated export or a mis-mapped column, not a real decision to remove hundreds of people.

Who Can Do What

Three separate permissions are involved, and it is normal for a sync to need two people.

| Action | Permission required | |---|---| | Upload a file, generate a preview, and read one | Import Members | | Confirm a preview that lists anybody as a deactivation candidate | Import Members and Deactivate Members | | See the candidates' names and email addresses | Also View Members |

Two things about this are worth knowing before you plan around it.

First, the confirm permission is based on whether the preview lists anybody, not on whether anybody will actually be deactivated. So a preview where the deactivation limit has already declined the sweep, and which says in as many words that nobody will be deactivated, still requires Deactivate Members to confirm. If you hold Import Members alone, the confirm button on that preview is disabled and the page explains why, so the work is not lost: review it, then send the link to a colleague who can apply it.

Second, an admin without View Members sees all the counts but not the list. In place of the names they get a notice explaining why it is hidden and suggesting they ask a colleague who has the permission to review it.

A preview that names nobody for deactivation needs only Import Members. Additive imports never produce a preview at all, so they only ever need that permission too.

Identity Resolution

Each row is matched to an existing member using two lookups:

  1. By orgMemberId. If the file supplies one and a member already has it, that member is updated.
  2. By email. If no member ID match is found, MentorNeko looks for an existing member with the same email address.

If neither finds a match, the row creates a new member.

This is why orgMemberId is strongly recommended for any organization that re-imports regularly. When somebody's email address changes in your system of record, the member ID keeps them matched to their existing account, their matches and their history, instead of creating a duplicate.

Import History

Every import is recorded below the upload area with its counts: rows created, updated, skipped, and errored, plus the individual error rows with their row numbers and the reason.

| Status | Meaning | |---|---| | In Progress | Still running. | | Completed | The run finished with no errored rows and no declined deactivation. Rows may still have been skipped, so check the skipped count rather than assuming every row landed. | | Partial | Some of it landed. Rows errored but others wrote, or nothing was written at all because every row was skipped, or a Full Roster Sync declined to deactivate anyone. | | Failed | The run did not complete. |

Two of these deserve a closer look.

Partial is the one that reports a real problem in a run that did not fail. The two most common causes are unreadable column headers and a declined deactivation.

Failed does not reliably mean "nothing happened", so read the note before re-running. Most failures are clean: a sync declined before any writes, or a file where every row errored, leaves your roster exactly as it was. But a run that gets most of the way through and then exhausts its retries on a later step can leave real changes behind, including members already deactivated and their matches already ended. When that is possible, the history note says so explicitly and tells you to review your members and matches before importing again. Take it at face value: re-running a destructive sync on the assumption that the first attempt did nothing is the one mistake this note exists to prevent.

REST Sync API

If you would rather not upload files by hand, MentorNeko exposes a REST endpoint that accepts the same roster data as JSON. It suits an HRIS, an association management system, or any platform that can make a scheduled HTTP call.

Getting a Key

Go to Admin > Settings and find the card titled Sync API Key (Advanced). Click Generate Key.

The key is shown once, at the moment you generate it, and cannot be retrieved afterwards. Copy it straight into your integration's secret store. If you lose it, use Regenerate Key, which immediately revokes the old one, or Revoke Key to switch the endpoint off entirely.

Treat the key like a password. It can rewrite your entire roster.

Organization Settings page showing the Sync API Key (Advanced) card with the Generate Key button and the automatic invitation toggle

Screenshot placeholder

Making a Request

Send a POST to /api/v1/organizations/{organizationId}/members/sync, authenticated with your key in an x-api-key header. The {organizationId} in the path is your organization's ID, not your subdomain.

Every request must also carry an Idempotency-Key header: an opaque string of your choosing, 1 to 200 characters, unique per request. Mint one key per HTTP request and reuse it only when retrying that exact request after a network failure or a retryable error. A retry with the same key and the same body is safe: it will not create a second job. Sending an old key with a different body is rejected with 409 Conflict, which is the API telling you a key was reused incorrectly rather than silently dropping data. If you batch a large roster across several requests, each request needs its own key.

The body carries a members array, plus an optional isFullSync flag that behaves like the Full Roster Sync checkbox. Each member accepts email, name, orgMemberId and membershipExpiry, an ISO 8601 date that is honoured on this path only and has no CSV equivalent. A role is accepted and ignored, exactly as in a CSV. If it is easier for your integration, emailAddress, fullName and memberId are accepted as alternative spellings of the first three.

Two differences from the CSV path are worth designing around:

  • A member without a name is rejected, not skipped. The API requires both an email and a name for every entry, and returns a validation error naming the offending entries. The silent-skip behaviour described earlier is specific to CSV files.
  • There is no preview and confirm stage. A request with isFullSync set is applied directly. The deactivation limit still protects you, but no human sees the list first. If you want that review step, use the CSV path.

Each request accepts up to 20,000 members and up to 4.5 MB, whichever limit is reached first. The size limit applies to the whole JSON body, so larger records can reach it before the member limit. The endpoint is rate limited to 10 requests per minute per organization.

Send larger rosters as multiple additive pages, each within both limits. Omit isFullSync or set it to false on every page, and use a separate Idempotency-Key for each page. Retry a page with its original key and unchanged body. Do not mark individual pages as full syncs: each request would be treated as a complete roster, not part of one.

Send only documented member fields. Extra fields do not update member profiles, count toward the request's size limit, and must remain unchanged when retrying the same page. An oversized body returns 413; more than 20,000 members returns 400.

Only additive requests may be split across several calls. Every request carrying isFullSync is treated as your complete roster on its own, so sending a full sync in chunks tells MentorNeko, once per chunk, that everyone in the other chunks is missing. A full sync must therefore fit in a single request. If your roster is too large for one, either send additive requests and handle departures another way, or use a CSV upload, which has a far larger practical capacity. The deactivation limit will usually catch a chunked full sync before it does real damage, but do not rely on it: it is a backstop against mistakes, not a supported way to work.

What the Response Tells You

A successful call returns 202 Accepted with a status of queued and an importAuditLogId identifying the run's row in Import History. The work then happens in the background.

That 202 means the job was confirmed as accepted for processing, or was already accepted earlier under the same idempotency key (in which case the status reads already_accepted and the same identifier is returned). If MentorNeko could not confirm that your payload was stored or that the job was queued, it returns 503 with a code of payload_upload_unconfirmed or queue_unconfirmed; retry with the same Idempotency-Key and the same body, and the retry picks up where the failed attempt left off without duplicating anything.

The response carries no result summary and there is no status endpoint to poll yet. Read the outcome of a sync in Import History, in the admin console, exactly as you would for a CSV upload.

That shapes what your integration should alert on. Watch for a non-2xx response: 4xx covers authentication problems, a missing or reused idempotency key, a malformed payload and an oversized body; 429 is rate limiting and 503 means retry. Then, separately, check the run's outcome in Import History using the returned identifier. Those are different failures: a 202 proves the job was queued, not that it succeeded, and a run that errors partway through reports itself in Import History and never in the response. A nightly sync that has not reached a completed state in Import History by morning is worth investigating even though nothing returned an error.

Inviting Synced Members

By default, members added by a sync land as Provisioned and unseated, exactly as they do from a CSV.

If you would rather your integration handle onboarding end to end, the same settings card carries a toggle, Automatically invite new members added via sync. With it on, eligible new members are emailed during your organization's 9 AM to 8 PM local send window, subject to email suppression and available seats. An overnight sync queues the invitations until that window opens. Updates to people who already exist never trigger an invitation.

This is an organization-wide setting, not a per-request option. Sending it as a field in the request body has no effect. Turning it off also stops invitations that are still queued in Provisioned status. Members already marked Invited keep their invitation.

When to Use It

The Sync API is a good fit for:

  • nightly or weekly automated syncs from an HRIS;
  • association management systems that already hold an authoritative membership roster;
  • any workflow where uploading a file by hand would be an ongoing operational burden.

For a broader look at how MentorNeko fits alongside your other systems, see Integrations and Data Sync.

Need more help?

Our team is here to help you get the most out of MentorNeko.

Contact Support