Syndicate Join Sessions
A join session lets you invite someone from your own site and have them become a member of a syndicate you manage — without ever handling their password, accreditation, or membership record. You mint a session bound to one email, the person completes the join on Wefunder, and you learn the outcome by polling the session or receiving join_session.* webhooks.
Sessions are addressed by their js_ id. They are install-scoped: you only ever see the sessions your own app's installation minted on the syndicate.
These endpoints are in preview. The hosted join page is rolling out; the shape below is stable.
Create a join session
POST /syndicates/:id/join_sessions
Requires write:syndicate_members (included in write:syndicates), at least operator standing in the syndicate, and an active installation of your app on it. Phase 1 supports mode: hosted only.
curl -X POST "https://api.wefunder.com/syndicates/syn_aB3xQ9k2vF8mNp1zT5wY7Qc4/join_sessions" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"join_session": {
"email": "[email protected]",
"name": "Jane Smith",
"require_approval": false,
"success_url": "https://partner.example.com/ok",
"cancel_url": "https://partner.example.com/cancel"
}
}'
| Field | Required | Notes |
|---|---|---|
email | yes | The address the session is bound to. |
name | no | Prefills the recipient's name. |
mode | no | hosted only (the default). |
display | no | redirect (default) or popup. |
require_approval | no | Whether the resulting membership needs manager approval before it is joined. |
success_url | no | HTTPS URL the recipient returns to after finishing. |
cancel_url | no | HTTPS URL the recipient returns to if they cancel. |
Response:
{
"data": {
"id": "js_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "join_session",
"attributes": {
"status": "pending",
"email": "[email protected]",
"name": "Jane Smith",
"mode": "hosted",
"display": null,
"ineligible_reason": null,
"require_approval": false,
"success_url": "https://partner.example.com/ok",
"cancel_url": "https://partner.example.com/cancel",
"url": "https://wefunder.com/join/session/js_3StSZhDjMHzn8NzEkX0kgEuN",
"expires_at": "2025-03-08T12:00:00Z",
"created_at": "2025-03-01T12:00:00Z"
}
}
}
Send the recipient to url. Each mint creates a fresh session; re-minting the same email reuses the underlying invitation (so the person is not emailed twice) but returns a new session.
Status values
pending · pending_approval · joined · rejected · ineligible · canceled · expired. When a session ends ineligible, ineligible_reason is one of accreditation_required, jurisdiction, blocked, club_unavailable (the syndicate is no longer joinable — it was deleted or converted to a group), or requires_investment (the syndicate requires a fund investment or paid subscription to join, which hosted join sessions don't support).
Errors
error.type | Meaning |
|---|---|
app_not_installed | Your app is not installed on this syndicate. |
syndicate_requires_subscription | This syndicate requires an annual subscription to join. |
unsupported_mode | Only hosted is supported in this phase. |
invalid_success_url / invalid_cancel_url | The URL is not https. |
List join sessions
GET /syndicates/:id/join_sessions
Returns the sessions your installation minted on this syndicate, newest first, paginated with the standard cursor / per_page contract. Needs read:syndicates.
Get a join session
GET /syndicates/:id/join_sessions/:id
Fetch one session by its js_ id to poll its current status. Needs read:syndicates.