Syndicate Members
The member directory: list and search it, invite, approve, moderate, reorder, and export. Reads need read:syndicates; writes need write:syndicates and at least operator standing in the syndicate (see the permission model).
Members are addressed by their mem_ id. Invitees who have not signed up yet are members too, with user set to null.
investment_total, amount, and total_amount are whole US dollars as strings: "15000" is $15,000.
List members
GET /syndicates/:id/members
curl "https://api.wefunder.com/syndicates/syn_aB3xQ9k2vF8mNp1zT5wY7Qc4/members?role=member&per_page=25" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response (as seen by a moderator):
{
"data": [
{
"id": "mem_7Hq2kLm9Pw3xZr5tYv8bNc4d",
"type": "syndicate_member",
"attributes": {
"user_id": 456,
"user": "usr_2mNp1zT5wY7Qc4aB3xQ9k2vF",
"user_name": "Jane Smith",
"role": "member",
"invite_role": "member",
"syndicate_permission": "full_access",
"title": null,
"sort_order": null,
"carry_percentage_override": null,
"carry_discount_percentage": null,
"management_fee_discount_percentage": null,
"public_on_syndicate_profile": true,
"joined_at": "2025-11-15T10:30:00Z",
"created_at": "2025-11-15T10:30:00Z",
"updated_at": "2026-02-10T14:00:00Z",
"user_email": "[email protected]",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/jane.jpg",
"bio": "Angel investor focused on climate tech",
"last_activity_at": "2026-03-08T09:15:00Z",
"profile_url": "/janesmith",
"tags": ["climate", "deep-tech"],
"interests": ["Climate"],
"stage_preferences": ["Seed"],
"looking_for": [],
"linkedin_url": "https://linkedin.com/in/janesmith",
"twitter_url": null,
"website": null,
"city": "San Francisco",
"state": "CA",
"country": "US",
"accredited": true,
"legal_name": "Jane A. Smith",
"starred": false,
"private_tags": ["LP prospect"],
"investment_total": "15000",
"deal_count": 2
}
}
],
"meta": {
"has_more": true,
"page_count": 25,
"next_cursor": 25
}
}
Pagination is by offset: pass meta.next_cursor back as cursor. per_page defaults to 25 and caps at 100.
Fields
| Field | Notes |
|---|---|
role | One of manager, member, backer, applicant, invitee, resigned, exiled, rejected |
syndicate_permission | full_access or operator. Meaningful only when role is manager; other rows carry the column default full_access, which grants nothing |
invite_role | The role the person was invited as (manager or member) |
carry_percentage_override | Integer 1 to 100, or null |
profile_url | A path relative to https://wefunder.com |
tags | The member's public "can help with" tags; interests, stage_preferences, and looking_for come from their investor profile |
city, state, country | Omitted when the member keeps their location private |
last_activity_at | The user's last login |
Profile fields (avatar_url, bio, location, links) are present only when the member has a Wefunder account.
Moderator-only fields
Users with full_access or operator standing see these; everyone else gets user_email as null and the rest omitted:
| Field | Description |
|---|---|
user_email | Email, or the invite email for an invitee |
accredited | Whether the user is an accredited investor |
legal_name | Full legal name |
starred | Whether the calling moderator starred this member |
private_tags | Labels moderators have attached to the member |
investment_total, deal_count | Dollars invested and distinct deals, across the syndicate's selected deals (one per company) |
Query parameters
| Param | Type | Description |
|---|---|---|
role | string | Filter by role, for example member, invitee, applicant, exiled |
permission | string | full_access or operator |
search | string | Matches name and bio. Moderators also match email and invite email |
sort | string | newest, oldest, alphabetical, last_activity, or investment_amount (moderators only). Default is directory order |
has_invested | "true" or "false" | Moderators only. Whether the member has invested in any selected deal |
accredited | "true" or "false" | Moderators only |
tag | string | A "can help with" tag, matched case-insensitively |
location | string | Matches city, state, or country for members with a public location |
cursor, per_page | integer | Pagination |
Moderator-only parameters are ignored, not rejected, for other callers.
Invite a member
POST /syndicates/:id/members/invite
Creates an invitee row and emails an invitation. The invitee becomes a member when they accept the link in that email.
{
"email": "[email protected]",
"name": "Jane Smith",
"syndicate_permission": "operator"
}
| Param | Required | Description |
|---|---|---|
email | Yes | Normalized to lowercase before matching |
name | No | Display name until the invitee signs up |
syndicate_permission | No | full_access invites a manager (invite_role: "manager"). operator, any other value, or omitting the field invites a regular member (invite_role: "member"); the row stores operator, which grants nothing on a non-manager row. Only the syndicate's creator can send a full_access invite |
This endpoint cannot invite an operator-tier co-manager. Operator standing belongs to a manager row with operator permission; the creator gets there by inviting with full_access (or promoting an existing member) and then demoting. The web app lets any full_access manager grant full_access; the API reserves it for the creator, and this page documents the API.
Returns 201 with the new member. Errors use the standard envelope; the error.type values are:
| Status | error.type | When |
|---|---|---|
400 | bad_request | email missing |
403 | forbidden | full_access requested by someone other than the creator (Only the syndicate manager can assign Admin roles) |
409 | conflict | The user is already an active member, or this email already has an open invitation |
Update a member
PATCH /syndicates/:id/members/:member_id
{
"member": {
"title": "Lead Investor",
"carry_percentage_override": 20
}
}
Sets a custom title and a per-member carry override (integer percent, 1 to 100). Requires operator standing, and the target must be someone you can manage: not the creator, and, unless you are the creator or a site admin, only if you hold full_access.
Approve an applicant
POST /syndicates/:id/members/:member_id/approve
Only rows with role applicant can be approved here; invitees accept their own link. The applicant joins with the role they applied for. Approving someone who applied as a manager requires full_access.
Approval also captures any fund payment the applicant authorized while waiting, so a 409 conflict is returned when the applicant is already approved and paying.
| Status | error.type | When |
|---|---|---|
400 | bad_request | Role is not applicant |
409 | conflict | Already approved |
Exile a member
POST /syndicates/:id/members/:member_id/hide
Sets the role to exiled, cancels any annual-subscription mandate, and releases any held fund payment. Requires operator standing and a manageable target (same rule as update). Returns the updated member.
Promote to manager
POST /syndicates/:id/members/:member_id/promote
Makes the member a manager with full_access. Creator (or site admin) only. Returns the updated member.
Demote to operator
POST /syndicates/:id/members/:member_id/demote
Reduces a manager's permission to operator. Requires full_access and a manageable target. Returns the updated member.
Restore a member
POST /syndicates/:id/members/:member_id/restore
Returns an exiled or resigned row to member. Requires operator standing. Any other role is refused with 400:
{
"error": {
"type": "bad_request",
"message": "Member is not resigned or exiled (role: member)",
"details": {},
"request_id": "req_3f9c2a1e8b7d4e5f9a1b2c3d"
}
}
Resend an invite
POST /syndicates/:id/members/:member_id/resend_invite
Re-sends the invitation email for a row whose role is still invitee. Returns {"data": {"resent": true}}. A non-invitee gets 400; an invitee with no invitation record gets 404.
Reorder members
POST /syndicates/:id/members/reorder
{
"member_ids": ["mem_7Hq2kLm9Pw3xZr5tYv8bNc4d", "mem_3dNc8bYv5tZr3xPw9mLk2qH7"]
}
Sets each listed member's sort_order to its position in the array. Returns {"data": {"reordered": true}}.
Remove a member (intent required)
Removal is irreversible, so DELETE /syndicates/:id/members/:member_id never removes anyone. It always returns 422:
{
"error": {
"type": "use_intents",
"message": "Removing members requires human approval. Use POST /api/v2/intents with action 'syndicates.remove_member'.",
"details": {},
"request_id": "req_3f9c2a1e8b7d4e5f9a1b2c3d"
}
}
The message names the application path; through https://api.wefunder.com that is POST /intents.
The removal itself is a syndicates.remove_member intent on the syndicate (resource_type: "Club"), approved by a human with full_access. To take a member out of the directory today without an intent, exile them with hide; that is reversible with restore.
A member's investments
GET /syndicates/:id/members/:member_id/investments
Moderators only. Lists the member's active investments in the syndicate's selected deals (one deal per company).
curl "https://api.wefunder.com/syndicates/syn_aB3xQ9k2vF8mNp1zT5wY7Qc4/members/mem_7Hq2kLm9Pw3xZr5tYv8bNc4d/investments" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
{
"data": [
{
"id": "inv_9kLm2Pw3xZr5tYv8bNc4dHq7",
"type": "member_investment",
"attributes": {
"fundraise_id": 99,
"offering": "ofr_kUlkWcWVugo7cSLD4RdD6gdK",
"company_name": "Acme Corp",
"amount": "15000",
"status": "confirmed",
"created_at": "2026-01-20T14:30:00Z"
}
}
],
"meta": {
"count": 1,
"total_amount": "15000"
}
}
status is pending (committed, not final) or confirmed (final). An invitee with no account returns an empty list. This endpoint is not paginated.
Export CSV
POST /syndicates/:id/members/export_csv
Moderators only. Responds with the directory as text/csv.
curl -X POST "https://api.wefunder.com/syndicates/syn_aB3xQ9k2vF8mNp1zT5wY7Qc4/members/export_csv" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-o members.csv