> For the complete documentation index, see [llms.txt](https://docs.joinflo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.joinflo.com/api-reference/user-api/members-api.md).

# Members API

## Import members into the given product

> Creates new members and updates existing members from CSV input for the\
> target \`product\`. A row whose \`Email\` matches an existing member in the\
> org is an update; every other row is a create. Returns \`200\` with a\
> \`MemberCsvImportResult\`, or a detailed validation result on \`400\`. A file\
> containing any invalid row is rejected as a whole.\
> \
> An import never removes anyone: members who already have access to the\
> product but are absent from the file keep it, and are listed in\
> \`absentMembers\` on the response. To remove them as part of the same\
> bulk-upload process, follow this call with\
> \`DELETE /members/bulk-remove\`, passing those emails.<br>

```json
{"openapi":"3.0.3","info":{"title":"Flo Recruit Web API — Members Import CSV","version":"1.0.0"},"servers":[{"url":"https://florecruit.com/api/v2","description":"Flo Recruit production API"}],"paths":{"/members/import-csv":{"post":{"tags":["members-API"],"summary":"Import members into the given product","description":"Creates new members and updates existing members from CSV input for the\ntarget `product`. A row whose `Email` matches an existing member in the\norg is an update; every other row is a create. Returns `200` with a\n`MemberCsvImportResult`, or a detailed validation result on `400`. A file\ncontaining any invalid row is rejected as a whole.\n\nAn import never removes anyone: members who already have access to the\nproduct but are absent from the file keep it, and are listed in\n`absentMembers` on the response. To remove them as part of the same\nbulk-upload process, follow this call with\n`DELETE /members/bulk-remove`, passing those emails.\n","operationId":"importProductMemberCsv","parameters":[{"name":"product","in":"query","required":true,"description":"Target product to import members into.","schema":{"type":"string","enum":["RECRUIT","PERFORM","UNI"]}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"CSV file containing member records. Must be less than 10MB in size.\nA header row is required, and each following row corresponds to one member.\nThe header must include the required columns below, as well as any optional\ncolumns containing values. Column matching is case-insensitive and\norder-independent; a header outside this set rejects the file.\n\nHeader row with every available column:\n`Employee ID,First Name,Last Name,Email,New Email,Job Title,Level,Office City,Office State (US Only),Office Country (Non-US Only),Department,Practice Area,Law School,Graduation Year,Effective Class Year,Start Date,Role,SSO ID,Use MFA,Bio Link,Work Arrangement,FLSA Status,Manager Email,Mentor Emails`\n\n- `Employee ID` — string, optional. Must be unique across rows.\n- `First Name` — string, required. Must not contain `\\`, `<`, `>`, `|`, `\"` or `` ` ``.\n- `Last Name` — string, required. Same disallowed characters as First Name.\n- `Email` — string, required. Must be unique and a well-formed email address.\n- `New Email` — string, optional. Must be a well-formed email address. On a row\n  whose `Email` matches an existing member, moves that member to this address; a\n  blank or unchanged value is a no-op, and a row matching no existing member is\n  rejected. No two rows may target the same address, and the address must not\n  already belong to another user or employee in the org. Only takes effect when\n  the bulk email-update feature is enabled for the organization.\n- `Job Title` — string, optional.\n- `Level` — string, optional. Only persisted when product is PERFORM.\n- `Office City` — string, optional.\n- `Office State (US Only)` — string, optional.\n- `Office Country (Non-US Only)` — string, optional.\n- `Department` — string, optional.\n- `Practice Area` — string, optional.\n- `Law School` — string, optional.\n- `Graduation Year` — string, optional. 4 digits within 200 years of the current\n  year. Only persisted when product is PERFORM.\n- `Effective Class Year` — string, optional. 4 digits within 200 years of the\n  current year. Only persisted when product is PERFORM.\n- `Start Date` — date, optional. Accepted formats: yyyy-MM-dd, yyyy/MM/dd,\n  M/d/yyyy, e.g. 2025-06-03.\n- `Role` — enum, optional. `ADMIN` or `MEMBER`. Defaults to `MEMBER`.\n- `SSO ID` — string, optional. Required only if the organization uses SSO and\n  does not use email as the SSO ID.\n- `Use MFA` — boolean string, optional. One of `true`, `t`, `false`, `f`, `1`,\n  `0`, `yes`, `no`, `y`, `n` (case-insensitive).\n- `Bio Link` — URL, optional.\n- `Work Arrangement` — enum, optional. `REMOTE`, `HYBRID` or `IN_PERSON`.\n- `FLSA Status` — enum, optional. One of `Exempt`, `Non-Exempt`,\n  `Not Applicable`, `EXEMPT`, `NON_EXEMPT` or `NOT_APPLICABLE`. Only persisted\n  when product is PERFORM.\n- `Manager Email` — string, optional. Only persisted when product is PERFORM.\n  Must be a well-formed email address matching a member already in the org or\n  another row in this file; row order does not matter. A member cannot be their\n  own manager. A blank value clears the member's manager; omitting the column\n  leaves it unchanged.\n- `Mentor Emails` — string, optional. Only persisted when product is PERFORM.\n  One or more email addresses separated by semicolons, e.g.\n  `kim@firm.com;raj@firm.com`. Each must be well-formed and match a member\n  already in the org or another row in this file; row order does not matter. A\n  member cannot be their own mentor, and a repeated address counts once. At most\n  50 mentors per member. The value replaces the member's mentors outright, so a\n  blank value clears them; omitting the column leaves them unchanged.\n"}}}}}},"responses":{"200":{"description":"Members imported successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberCsvImportResult"}}}},"400":{"description":"Invalid member data — file-level and/or row/column-level validation errors.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembersCsvValidationResult"}}}},"401":{"description":"Unauthorized — authentication failed or session missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden — the session is not permitted to import members into this product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"MemberCsvImportResult":{"type":"object","properties":{"createdCount":{"type":"integer","format":"int32","description":"Number of new members created by this import."},"updatedCount":{"type":"integer","format":"int32","description":"Number of existing members updated by this import."},"absentMembers":{"type":"array","description":"Every non-admin member who already has access to this product but did\nnot appear in the uploaded CSV. An import never removes anyone, so use\nthis list to decide who to pass to `DELETE /members/bulk-remove` if the\nupload is meant to be authoritative. Empty when the CSV covered\neveryone.\n","items":{"$ref":"#/components/schemas/AbsentMember"}}}},"AbsentMember":{"type":"object","properties":{"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"}}},"MembersCsvValidationResult":{"type":"object","properties":{"fileError":{"$ref":"#/components/schemas/FileError"},"rowColumnErrors":{"type":"array","items":{"$ref":"#/components/schemas/RowColumnError"}}}},"FileError":{"type":"object","nullable":true,"properties":{"message":{"type":"string"},"type":{"type":"string","enum":["EMPTY_FILE","INVALID_FILE_FORMAT","MISSING_REQUIRED_COLUMNS","UNEXPECTED_COLUMNS","FILE_SIZE_EXCEEDED"]}}},"RowColumnError":{"type":"object","properties":{"columnName":{"type":"string"},"message":{"type":"string"},"rowNumber":{"type":"integer","format":"int32"},"type":{"type":"string","enum":["EMPTY_REQUIRED_VALUE","INVALID_EMAIL","INVALID_FORMAT","INVALID_URL","INVALID_YEAR","INVALID_DATE_FORMAT","DUPLICATE_VALUE","EXISTING_USER_CONFLICT","INVALID_LIST_SELECTION","INVALID_SSO_ID","ROW_VALUE_CONFLICT","UNKNOWN"]},"value":{"type":"string"}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}}}}}
```
