Wefunder API Reference
Complete reference for the Wefunder API. Build integrations, track investments, and manage campaigns programmatically.
https://api.wefunder.com/api/v2Authentication
The Wefunder API uses OAuth 2.0 Bearer tokens for authentication. Include your access token in the Authorization header of every request.
OAuth Scopes
read:publicView public deal data (no account needed)read:exploreView the deals you can see on Wefunderread:profileView your basic profile and the companies you followread:profile:followsView the companies you followwrite:profileUpdate your profilewrite:followsFollow and unfollow companieswrite:commentsDraft questions, answers, and comments for your approvalread:investmentsView investments and TTW reservations you can accessread:companiesView company info and offerings you can access, including the investor roster of a company you help runread:invite_linksSee the investment links your app created and who used themwrite:invite_linksCreate investment links to your offeringsread:investment_sessionsView hosted investment sessions for your offeringswrite:investment_sessionsCreate and cancel hosted investment sessionsread:webhooksView your app's webhook endpoints and delivery historywrite:webhooksCreate, update, and remove your app's webhook endpointsread:installationsView where your app is installedwrite:installationsInstall and uninstall your app on companies and syndicates you can editread:syndicatesView syndicate deals and memberswrite:syndicatesManage syndicate deals and memberswrite:syndicate_membersManage syndicate memberscurl https://api.wefunder.com/api/v2/users/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": 123,
"type": "user",
"attributes": {
"email": "[email protected]",
"username": "investor123",
"name": "Jane Doe"
}
}
}Explore
/exploreList public offerings
Returns the offerings shown on wefunder.com/explore — the curated set of companies that
meet Wefunder's discoverability bar (a soft-confirmed traction threshold plus approval),
one offering per company. An "offering" is a fundraise, addressed by its id
(ofr_...).
Public view (read:public). Reachable with either a server-side (client_credentials)
token or a user access token. Private rounds (e.g. Reg D 506(b)) are never listed, and
low-traction or unapproved companies are excluded — exactly as they are on the website
for a logged-out visitor.
Logged-in view (read:explore). A user access token carrying read:explore gets
what that user sees on wefunder.com/explore: the public offerings plus any the user
qualifies for (accredited-only / Vault deals, invited private rounds), each checked
against the same visibility policy the website applies. The response is a strict
superset of the public one — same fields and ids — with two extra attributes,
publicly_visible and invested, and meta.personalized: true. A server-side key can
never hold read:explore; a token with read:explore but no resolvable user gets the
public view.
Order with sort (default: most raised); paginate with cursor and per_page.
meta.total_count is the number of offerings across all pages, after filters.
Closed rounds (status). By default the list is live rounds. status=closed lists
rounds that finished raising instead, newest closed_at first. It is not limited to one
per company or to the curated explore set: it covers every finished round that
GET /offerings/{id} serves to a logged-out visitor, for companies listed in Wefunder's
public directory. status=all returns the live list first, then the closed list. With
status=closed or status=all, exemption is the only filter accepted, and sort
orders only the live part. Closed rounds follow the public view even for a
read:explore token.
Filters are objective, per-offering terms — exemption family, security type,
TTW vs. live, minimum investment ceiling, close date, amount raised floor. The response
echoes the applied set in meta.filters. An out-of-vocabulary value is a 400 naming
the accepted values. There are deliberately no relevance, quality, or ranking criteria.
Use this endpoint to:
- Discover and monitor active deals
- Build deal aggregators and public listings
- Bulk-list closed rounds (
status=closed)
Parameters
stringper_pageintegerqueryOfferings per page.
statusstringqueryWhich rounds to list:
live(default): rounds accepting investments or reservations, as on wefunder.com/exploreclosed: rounds that finished raising, newestclosed_atfirst (id breaks ties)all: the live list, then the closed list
Any other value is a 400.
sortstringqueryOrdering of live rounds. A 400 with status=closed; with status=all it orders the live part only.
most_raised(default) — highest amount raised firstclosing_soon— soonest funding close firstnewest— most recently launched firstmost_investors— highest investor count first
exemptionstringqueryOnly offerings under this SEC exemption family. Reg CF and Reg D are the supported public filters.
securitystringqueryOnly offerings issuing this kind of security — the security.type value on results.
testing_the_watersbooleanqueryfalse — only live rounds accepting investments; true — only Testing-the-Waters rounds collecting non-binding reservations.
max_min_investmentnumberqueryOnly offerings whose minimum investment is at most this amount (USD).
closing_beforestringqueryOnly offerings whose funding close date is on or before this date (ISO 8601). Offerings with no close date are excluded.
min_amount_raisednumberqueryOnly offerings that have raised at least this amount so far (USD).
industryarrayqueryOnly companies tagged with any of these industries — the curated tags the wefunder.com
explore page filters by (see each offering's industries). One value or a comma-separated
list; unknown values are a 400 listing the vocabulary. Objective facets, not a ranking.
business_modelarrayqueryOnly companies with any of these business models (see each offering's business_models). One value or a comma-separated list.
followedbooleanqueryLogged-in view only (read:explore with a user). true — only companies the
authorizing user follows on wefunder.com (their watchlist); false — only companies
they do not follow. A 400 on the public view, which has no user to filter by.
Responses
curl https://api.wefunder.com/api/v2/explore?per_page=value&status=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "ofr_yw3OhusvpfJP4Pk3wRYV1F2R",
"type": "offering",
"attributes": {
"company_name": "ZeroBorder Self-Banking Centers",
"tagline": "Example tagline",
"url": "https://wefunder.com/zeroborder",
"card_image_url": "https://uploads.wefunder.com/uploads/company/custom_card_photo/189517/large_card.jpg",
"logo_url": "https://uploads.wefunder.com/uploads/company/logo/189517/large_logo.png",
"exemption": {
"family": "reg_cf",
"subtype": null,
"label": "Reg CF"
},
"security": null,
"intended_security": {
"type": "safe",
"label": "SAFE"
},
"industries": [
{
"type": "robotics",
"label": "Robotics"
}
],
"business_models": [
{
"type": "robotics",
"label": "Robotics"
}
],
"status": "open",
"testing_the_waters": false,
"funding_target": "1000000",
"funding_target_cents": 100000000,
"max_funding_target": "1235000",
"max_funding_target_cents": 123500000,
"min_investment": "100",
"min_investment_cents": 10000,
"amount_raised": "642300",
"amount_raised_cents": 64230000,
"investor_count": 1203,
"started_at": "2025-03-01T12:00:00Z",
"closes_at": "2025-04-30T03:59:59Z",
"closed_at": "2025-03-01T12:00:00Z",
"form_c_url": "https://www.sec.gov/Archives/edgar/data/1834121/000167025425000123/0001670254-25-000123-index.htm",
"spv_legal_name": "WF ZeroBorder 2025, a series of Wefunder SPV, LLC",
"publicly_visible": true,
"invested": false,
"followed": false
},
"company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"warnings": [
{
"code": "prior_rounds",
"message": "This company completed 2 earlier rounds on Wefunder. amount_raised and investor_count cover this offering only, not the company's lifetime total."
}
],
"etag": "a1b2c3d4e5f6"
}
],
"meta": {
"total_count": 119,
"page_count": 25,
"has_more": true,
"status": "live",
"sort": "most_raised",
"personalized": false,
"filters": {
"security": "safe",
"testing_the_waters": false
},
"next_cursor": 25
}
}/offerings/{external_id}Get a public offering
Retrieves a single offering by its id (ofr_...).
With read:public, a valid id for a non-public offering (e.g. a private Reg D 506(b)
round) returns 404 — having an id does not make an offering publicly resolvable. With
read:explore on a user access token, the offering resolves if that user may see it on
wefunder.com (e.g. an accredited-only or invited round), and the response gains
publicly_visible and invested.
Parameters
external_idstringrequiredpathThe offering's id (ofr_...).
Responses
curl https://api.wefunder.com/api/v2/offerings/ofr_yw3OhusvpfJP4Pk3wRYV1F2R \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "ofr_yw3OhusvpfJP4Pk3wRYV1F2R",
"type": "offering",
"attributes": {
"company_name": "ZeroBorder Self-Banking Centers",
"tagline": "Example tagline",
"url": "https://wefunder.com/zeroborder",
"card_image_url": "https://uploads.wefunder.com/uploads/company/custom_card_photo/189517/large_card.jpg",
"logo_url": "https://uploads.wefunder.com/uploads/company/logo/189517/large_logo.png",
"exemption": {
"family": "reg_cf",
"subtype": null,
"label": "Reg CF"
},
"security": null,
"intended_security": {
"type": "safe",
"label": "SAFE"
},
"industries": [
{
"type": "robotics",
"label": "Robotics"
}
],
"business_models": [
{
"type": "robotics",
"label": "Robotics"
}
],
"status": "open",
"testing_the_waters": false,
"funding_target": "1000000",
"funding_target_cents": 100000000,
"max_funding_target": "1235000",
"max_funding_target_cents": 123500000,
"min_investment": "100",
"min_investment_cents": 10000,
"amount_raised": "642300",
"amount_raised_cents": 64230000,
"investor_count": 1203,
"started_at": "2025-03-01T12:00:00Z",
"closes_at": "2025-04-30T03:59:59Z",
"closed_at": "2025-03-01T12:00:00Z",
"form_c_url": "https://www.sec.gov/Archives/edgar/data/1834121/000167025425000123/0001670254-25-000123-index.htm",
"spv_legal_name": "WF ZeroBorder 2025, a series of Wefunder SPV, LLC",
"publicly_visible": true,
"invested": false,
"followed": false
},
"company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"warnings": [
{
"code": "prior_rounds",
"message": "This company completed 2 earlier rounds on Wefunder. amount_raised and investor_count cover this offering only, not the company's lifetime total."
}
],
"etag": "a1b2c3d4e5f6"
}
}/companies/{id}/disclosuresGet a company's public Form C disclosures
The Details tab of the company's Wefunder page as structured data — the company's own Form C disclosures, section for section: financial statements for the fiscal years on file, the page's ratios, the founder's current-position disclosure (cash on hand, monthly revenue / costs / burn), the financial-condition narrative, document links, risks, use of funds, directors and officers, 20%+ holders, capital structure, prior offerings, outstanding notes and debts, and related-party transactions.
Same "who has a page" rule as GET /companies/{id}. The round read is the page's own: the
display round for the viewer, swapped for its concurrent Reg CF sibling on a Reg D round,
and only when it is a Reg CF / ECSP round with a Form C. A company with no such round has
no details tab on the site and answers 404 with error.type: no_disclosures — distinct
from an unknown or hidden company. A section the company hides on the site is null.
Money is decimal strings, never USD by assumption: the round's own figures (use of funds,
prior offerings, notes, debts, related parties) are in currency — EUR for an ECSP round —
while the Form C financial statements, the ratio derived from them, and the current-position
figures (which repeat it as current_position.currency) are in financials_currency, the
currency the issuer declared for its statements (it can differ from
the round's: DKK, RON, GBP, or USD statements behind a EUR round). Ratios are percentages as
decimal strings. Everything here is the issuer's own disclosure, served as filed, not a
Wefunder assessment.
Parameters
idstringrequiredpathsectionsarrayqueryOnly these sections (offering_id, currency, financials_currency and filing are always
included). Omit for the whole tab; a disclosure-heavy company runs to ~100 KB. Unknown names
are a 400 listing the vocabulary.
Responses
curl https://api.wefunder.com/api/v2/companies/co_8Kd0aB3xQ9k2vF8mNp1zT5wY/disclosures?sections=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "company_disclosures",
"attributes": {
"offering_id": "string",
"currency": "USD",
"financials_currency": "USD",
"filing": {
"exemption": {
"family": "reg_cf",
"subtype": null,
"label": "Reg CF"
},
"sec_filing_url": "string",
"filed": true,
"statement_date": "string",
"fiscal_year_end": "string"
},
"business": {
"legal_name": "string",
"legal_form": "string",
"jurisdiction": "string",
"incorporated_on": "string",
"employees": 123
},
"financial_statements": {
"most_recent": {
"total_assets": "string",
"cash_and_equivalents": "string",
"accounts_receivable": "string",
"current_liabilities": "string",
"non_current_liabilities": "string",
"short_term_debt": "string",
"long_term_debt": "string",
"revenue": "string",
"cost_of_goods_sold": "string",
"taxes_paid": "string",
"net_income": "string"
},
"prior": {
"total_assets": "string",
"cash_and_equivalents": "string",
"accounts_receivable": "string",
"current_liabilities": "string",
"non_current_liabilities": "string",
"short_term_debt": "string",
"long_term_debt": "string",
"revenue": "string",
"cost_of_goods_sold": "string",
"taxes_paid": "string",
"net_income": "string"
},
"prior_prior": {
"total_assets": "string",
"cash_and_equivalents": "string",
"accounts_receivable": "string",
"current_liabilities": "string",
"non_current_liabilities": "string",
"short_term_debt": "string",
"long_term_debt": "string",
"revenue": "string",
"cost_of_goods_sold": "string",
"taxes_paid": "string",
"net_income": "string"
}
},
"ratios": {
"net_margin_percent": "string",
"gross_margin_percent": "string",
"return_on_assets_percent": "string",
"liabilities_to_assets_percent": "string",
"debt_to_assets_percent": "string",
"cash_to_assets_percent": "string",
"revenue_per_employee": "string"
},
"current_position": {
"currency": "DKK",
"cash_on_hand": "string",
"cash_on_hand_as_of": "string",
"average_monthly_revenue": "string",
"average_monthly_cost_of_goods": "string",
"average_monthly_expenses": "string",
"average_monthly_burn": "string"
},
"financial_condition": "string",
"financial_statement_documents": [
{
"name": "string",
"url": "string"
}
],
"investment_documents": [
{
"name": "string",
"url": "string"
}
],
"risks": [
"string"
],
"use_of_funds": [
{
"if_raised": "string",
"plan": "string"
}
],
"directors": [
{
"name": "string",
"titles": "string",
"since": 123,
"director": true,
"officer": true
}
],
"officers": [
{
"name": "string",
"titles": "string",
"since": 123,
"director": true,
"officer": true
}
],
"voting_power": [
{
"name": "string",
"holding": "string",
"voting_power_percent": "string"
}
],
"capital_structure": [
{
"class_of_security": "string",
"authorized": "string",
"outstanding": "string",
"voting_rights": "string",
"other_rights": "string"
}
],
"prior_offerings": [
{
"date": "string",
"exemption": "string",
"security_type": "string",
"amount_sold": "string",
"use_of_proceeds": "string",
"offering_id": "string"
}
],
"outstanding_notes": [
{
"amount": "string",
"outstanding_principal": "string",
"valuation_cap": "string",
"uncapped": true,
"interest_rate_percent": "string",
"discount_percent": "string",
"maturity_date": "string",
"description": "string"
}
],
"outstanding_debts": {
"note": "string",
"items": [
{
"original_amount": "string",
"outstanding_principal": "string",
"current_with_payments": true,
"maturity_date": "string",
"description": "string"
}
]
},
"related_parties": {
"description": "string",
"parties": [
{
"name": "string",
"relationship": "string",
"amount": "string",
"date": "string",
"outstanding_principal": "string",
"description": "string"
}
]
}
}
}
}/companies/{id}/pitchGet a company's pitch
The Overview tab's pitch as structured data: the story as ordered blocks (heading,
paragraph, list, image, video, footnote), plus the perk tiers of the round the page
shows the viewer. Images and embedded videos keep their place in the document with an absolute
URL, because founders publish perk tiers, stretch goals, timelines, and charts as pictures
(typically with no alt text) and a plain-text rendering would drop them.
What is parsed is what the page renders: the story passes through the site's own sanitizer
first, so an embed the page refuses (a host off its allowlist, a javascript: URL) is never
served here either. Same "who has a page" rule and round chooser as GET /companies/{id}.
A site-public company with no round the viewer may see still has a pitch (perks: null).
perks.described_in_pitch is a heuristic: true when the structured perk list is a placeholder
("See investor overview page", or one identical sentence on every tier) and the real tiers are
in the story's images.
authored_by says who wrote the story: company (the issuer's own words and imagery, not a
Wefunder assessment) or wefunder (a Wefunder-prepared deal memo the company did not
participate in; disclaimer carries the page's notice). A pitch can run to ~70 KB; use
sections to ask for less.
Parameters
idstringrequiredpathsectionsarrayqueryOnly these sections (offering_id, title, url, authored_by, and disclaimer are
always included). Omit for the whole pitch. Unknown names are a 400 listing the vocabulary.
Responses
curl https://api.wefunder.com/api/v2/companies/co_8Kd0aB3xQ9k2vF8mNp1zT5wY/pitch?sections=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "company_pitch",
"attributes": {
"offering_id": "string",
"title": "string",
"url": "string",
"authored_by": "company",
"disclaimer": "string",
"story": {
"blocks": [
{
"type": "heading",
"level": 123,
"text": "string",
"number": 123,
"ordered": true,
"start": 123,
"items": [
"string"
],
"links": [
{
"text": "string",
"url": "string"
}
],
"url": "string",
"link": "string",
"alt": "string",
"filename": "string",
"provider": "string"
}
],
"image_count": 123,
"video_count": 123,
"inline_images_omitted": 123,
"character_count": 123
},
"perks": {
"offering_id": "string",
"currency": "string",
"described_in_pitch": true,
"tiers": [
{
"qualifying_amount": "string",
"description": "string"
}
]
}
}
}
}/companies/{id}/updatesList a company's posts
The company page's Posts tab as data: the published updates, notes, and spotlights the
viewer may see, pinned first then newest, with a plain-text excerpt each. With
read:explore the viewer is the authorizing user, so a follower or investor sees the
community- and investors-only posts the site shows them; with read:public it is the
anonymous view. Same query as the tab (FeedItem.viewable_by); investments, Q&A threads,
and investor quotes belong to other tabs and are not here. Fetch one post in full with
GET /companies/{id}/updates/{update_id}. Posts are the issuer's own words.
Parameters
idstringrequiredpathcursorstringqueryper_pageintegerqueryResponses
curl https://api.wefunder.com/api/v2/companies/co_8Kd0aB3xQ9k2vF8mNp1zT5wY/updates?cursor=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "string",
"type": "company_update",
"attributes": {
"kind": "string",
"title": "string",
"excerpt": "string",
"content": "string",
"published_at": "string",
"pinned": true,
"visibility": "public",
"author": {
"name": "string"
},
"comments_count": 123,
"likes_count": 123,
"url": "string"
}
}
],
"meta": {
"company": "string",
"has_more": true,
"page_count": 123,
"next_cursor": 123
}
}/companies/{id}/updates/{update_id}Get one company post in full
One post with its full plain-text content, by the id the list returned. Same visibility as the list; a post the tab would not show this viewer is a 404.
Parameters
idstringrequiredpathupdate_idstringrequiredpathResponses
curl https://api.wefunder.com/api/v2/companies/{id}/updates/{update_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "company_update",
"attributes": {
"kind": "string",
"title": "string",
"excerpt": "string",
"content": "string",
"published_at": "string",
"pinned": true,
"visibility": "public",
"author": {
"name": "string"
},
"comments_count": 123,
"likes_count": 123,
"url": "string"
}
}
}/companies/{id}/questionsList a company's investor questions and answers
The company page's Ask tab as data: the questions investors asked and the answers, as the
tab lists them for this viewer (the same repository and visibility as the site). Like the tab,
questions default to the current raise — those asked since it opened (meta.questions_since);
past_raises=true includes every raise, which the site offers to any visitor because
past-raise questions are public. sort is the tab's dropdown: relevance (default:
highlighted, then answered, then most liked), recent, upvoted, unanswered. Text is plain.
Questions and answers carry their id (cmt_...); the integer key never leaves the API.
Answers are the founders' own words.
q searches question and answer text (Postgres full text: quoted phrases and -word work;
one- or two-word queries also prefix-match) and replaces the sort with match rank —
meta.sort is then search and each result's match says whether its question or an
answer matched. unanswered_by_team=true keeps only questions with no live answer from the
company's team (the founder's queue; the unanswered sort merely orders by whether anyone
replied).
Parameters
idstringrequiredpathsortstringquerypast_raisesbooleanqueryqstringqueryFull-text search over questions and answers. At most 200 bytes.
unanswered_by_teambooleanquerycursorstringqueryper_pageintegerqueryResponses
curl https://api.wefunder.com/api/v2/companies/co_8Kd0aB3xQ9k2vF8mNp1zT5wY/questions?sort=value&past_raises=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "cmt_m2JkUx7E3aBFscGMKDdJ9saR",
"type": "company_question",
"attributes": {
"question": "string",
"asked_at": "string",
"asked_by": {
"id": "usr_7Hk2mPq9rT4vX1yB3nC5dF8g",
"name": "string",
"role": "string",
"team": true
},
"likes_count": 123,
"highlighted": true,
"answered_by_team": true,
"match": "question",
"answers": [
{
"id": "string",
"answer": "string",
"answered_at": "string",
"answered_by": {
"id": "usr_7Hk2mPq9rT4vX1yB3nC5dF8g",
"name": "string",
"role": "string",
"team": true
},
"likes_count": 123
}
],
"url": "string"
}
}
],
"meta": {
"company": "string",
"sort": "string",
"q": "string",
"unanswered_by_team": true,
"past_raises": true,
"questions_since": "string",
"total": 123,
"has_more": true,
"page_count": 123,
"next_cursor": 123
}
}/companies/{id}Get a company page
The company page behind an offering, as structured data — the "click a company" step after
/explore. Addressed by the co_... id every offering carries in its top-level company field (a bare string).
Keeps apart the three raised numbers the page shows and readers conflate:
current_raise.amount_raised (this campaign's live rounds combined, on Wefunder),
past_rounds[] (prior rounds the page lists, each tagged source: wefunder for rounds
observed here or reported for founder-disclosed off-platform rounds), and
totals.profile_total_raised (the number on the page's ticker bar). Every figure comes
from the same policy the page uses, so the API never disagrees with the site.
Who has a page. Every company whose profile wefunder.com lists publicly — the same set
the site's search bar returns (published, not invite-only, searchable or with a live Form C;
accredited-only companies need an accredited viewer) — plus the /explore set. A funded
company, or one the viewer may see no round of, renders with raising: false and
current_raise: null; its history is in wefunder_rounds. Logged-in view
(read:explore) additionally covers the vault / syndicate-led companies the site shows an
accredited viewer, and the round described is the one the page would show that viewer. A
valid id for a company outside the viewer's set is a 404, never a partial payload.
Parameters
idstringrequiredpathThe company's id (co_...).
Responses
curl https://api.wefunder.com/api/v2/companies/co_8Kd0aB3xQ9k2vF8mNp1zT5wY \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"type": "company",
"attributes": {
"name": "string",
"tagline": "string",
"url": "string",
"logo_url": "string",
"card_image_url": "string",
"location": {
"city": "string",
"state": "string",
"country": "string"
},
"legal_name": "Acme Robotics, Inc.",
"legal_form": "Corporation",
"website_url": "https://acme.example",
"twitter_url": "https://twitter.com/acme",
"linkedin_url": "https://linkedin.com/company/acme-robotics",
"facebook_url": "https://facebook.com/acme",
"instagram_url": "https://instagram.com/acme",
"promotion_opt_in": true,
"raising": true,
"current_raise": null,
"past_rounds": [
{
"offering_id": "string",
"source": "wefunder",
"exemption": {
"family": "reg_cf",
"subtype": null,
"label": "Reg CF"
},
"amount_raised": "string",
"amount_raised_cents": 123,
"investor_count": 123,
"opened_at": "string",
"closed_at": "string"
}
],
"wefunder_rounds": [
{
"offering_id": "string",
"current": true,
"status": "open",
"exemption": null,
"security": null,
"amount_raised": "string",
"amount_raised_cents": 123,
"investor_count": 123,
"opened_at": "string",
"closed_at": "string"
}
],
"totals": {
"raised_on_wefunder_all_time": "string",
"raised_on_wefunder_all_time_cents": 123,
"profile_total_raised": "string",
"profile_total_raised_cents": 123,
"profile_reported_off_platform": "string",
"profile_reported_off_platform_cents": 123,
"profile_includes_past_rounds": true
}
}
}
}Companies
/companies/searchSearch companies by name
The wefunder.com search bar, companies only. Same Algolia request, same result ordering,
and same page size as the site's top bar, so the results are what a visitor typing the
same text would see, in that order — companies raising now and companies funded in the
past, whether or not they appear on /explore. The order is the site's search order
(match quality first, then the site's tie-breaks); nothing here recommends.
Each result carries the company's co_ id for GET /companies/{id}. With read:explore
the accreditation gate matches the authorizing user (an accredited viewer sees the
accredited-only companies the site would show them); with read:public it is the
anonymous view.
Parameters
qstringrequiredqueryThe company name, or part of it. At most 200 characters and 500 bytes.
limitintegerqueryMaximum results, 1–20. Default 8, the same as the site.
Responses
curl https://api.wefunder.com/api/v2/companies/search?q=value&limit=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"type": "company",
"attributes": {
"name": "Acme Robotics",
"tagline": "string",
"url": "https://wefunder.com/acme",
"logo_url": "string",
"raising": true,
"profile_available": true
}
}
],
"meta": {
"query": "string",
"count": 123
}
}Users
/users/meGet current user profile
Retrieves the profile information for the currently authenticated user. This endpoint returns basic user details including name, email, and account status.
Use this endpoint to:
- Display user information in your application
- Verify the identity of the authenticated user
- Check user account status and permissions
The response includes the user's unique ID which can be used to reference the user in other API calls.
Two shapes, depending on the token:
- With
read:profile(orwrite:profile): the full profile shown in the example. - Any other user token: only the user's id and type,
{"data": {"id": "usr_...", "type": "user"}}, with noattributes. Use it to learn whose token you hold; it never includes the email, name, username or city.
A token with no user (a server-side client_credentials key, or an installation acting
as a company or syndicate) gets 403. Before this change a user token without
read:profile got 403 here too; code that read attributes unconditionally should
now check for it.
Responses
curl https://api.wefunder.com/api/v2/users/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"type": "user",
"attributes": {
"email": "[email protected]",
"username": "john_doe",
"name": "John",
"full_name": "John Doe",
"bio": "Entrepreneur and investor",
"city": "San Francisco",
"country": "USA",
"avatar_url": "https://example.com/avatar.jpg",
"created_at": "2023-01-15T10:30:00Z",
"certified_at": "2023-02-01T14:20:00Z"
}
}
}/users/me/companiesList the companies you edit
The companies the authenticated user is a founder or team member of — precisely the
companies the founder-scoped endpoints under /companies/{company_id}/... (dashboard,
investors, fundraises) will accept. Anyone else's company returns 403 there, so call this
first to learn which co_ ids you hold. Not paginated.
raising is true when the company has a round currently accepting investments or
reservations. roles are the user's roles on the company (founder, employee, ...).
Responses
curl https://api.wefunder.com/api/v2/users/me/companies \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"type": "company",
"attributes": {
"name": "Acme Robotics",
"tagline": "string",
"url": "https://wefunder.com/acme",
"roles": [
"founder"
],
"raising": true
}
}
],
"meta": {
"count": 123
}
}/users/me/followsList the companies you follow
The authenticated user's watchlist — the companies they follow on wefunder.com (the same
rows the site's Follow button writes), newest first. Each entry is in the search-result
shape (co_ id, name, tagline, URL, logo, raising, profile_available) plus
followed_at.
Accepts read:profile or write:follows. Both include read:profile:follows, the
follows list on its own, which is what this endpoint checks. A token holding only
write:follows can list its follows here but cannot read the profile (GET /users/me).
Which companies are listed depends on the grant, the same way the follow list on a user's public Wefunder profile does:
write:follows,read:mcp(or the retiredread:follows): the full list, every company the user follows. An app that follows and unfollows for the user, or the user's own AI assistant acting as them, sees what the user sees.read:profileorwrite:profilewithout one of those: the public list. A company that has asked not to be promoted (promotion_opt_infalse onGET /companies/{id}) is left out, exactly as it is left out of the profile's follow list for every visitor but the user. This holds for every user, admins included.
The filter is applied before paging, so it never shortens a page, and page_count counts
the rows returned.
Parameters
cursorstringqueryper_pageintegerqueryResponses
curl https://api.wefunder.com/api/v2/users/me/follows?cursor=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"type": "company",
"attributes": {
"name": "string",
"tagline": "string",
"url": "string",
"logo_url": "string",
"raising": true,
"profile_available": true,
"followed_at": "string"
}
}
],
"meta": {
"page_count": 25,
"has_more": true,
"next_cursor": 12345
}
}/users/me/follows/{company_id}Follow a company
Follow the company for the authenticated user — exactly what pressing Follow on its
Wefunder page does, side effects included (the company counts the user as a follower and
may be notified; the user receives the company's updates). Idempotent: following an
already-followed company returns changed: false. 404 for a company the site would not
show this user. Requires write:follows, which the user grants explicitly; it is never
implied by read:mcp.
Parameters
company_idstringrequiredpathResponses
curl -X PUT https://api.wefunder.com/api/v2/users/me/follows/co_8Kd0aB3xQ9k2vF8mNp1zT5wY \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "follow_state",
"attributes": {
"followed": true,
"changed": true
}
}
}/users/me/follows/{company_id}Unfollow a company
Unfollow the company for the authenticated user. Idempotent (changed is false when they were not following it). No visibility gate: a follow you hold is always undoable, even for a company since hidden. Requires write:follows.
Parameters
company_idstringrequiredpathResponses
curl -X DELETE https://api.wefunder.com/api/v2/users/me/follows/co_8Kd0aB3xQ9k2vF8mNp1zT5wY \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "follow_state",
"attributes": {
"followed": true,
"changed": true
}
}
}Investments
/investmentsList or sync investments
The investment records the token may see, served from published state (docs: Investments: list, sync, retrieve). The audience is the union of the companies the token's user edits (their founder-visible records) and the user's own investments (every applied record of theirs, whatever its status). Filters narrow within that audience; they never widen it.
Three ways to call it:
- List (no
cursor, noupdated_since): the current records, tombstones excluded, ordered by investment. Page withmeta.next_cursorwhilemeta.has_more; the final page's cursor is a sync cursor positioned at the moment the listing started. - Sync by cursor: only the records whose published state changed since the cursor,
one record per investment, tombstones included (
visible: falsewithid,observed_at,cursorandreason, and no payload fields). Apply incursororder; always storemeta.next_cursor. Filters are not encoded in the cursor: repeat the samecompany_id,offering_idorinvestor_idon every sync request, or the sync widens to the whole audience. - Sync by time:
updated_since=<ISO 8601>is sugar for a cursor at the ledger position just before that time (with a 60 s safety margin). The response is a normal sync page, so continue with itsmeta.next_cursor.
Records are eventually consistent (about ten minutes on the common paths); each carries
observed_at. GET /investments/{id} returns the same shape derived now. Investor
identity fields on other investors' records require read:investors:pii; a user always
sees their own. Money is integer minor units plus amounts.currency.
410 Gone means the cursor or updated_since predates the 90-day retention window:
list again and replace your dataset. status cannot be combined with sync (a record
leaving the status would never be delivered).
Parameters
company_idstringqueryCompany external id (co_…).
offering_idstringqueryOffering external id (ofr_…). In sync mode an investment that moved to another
offering is delivered once more as a tombstone under this filter.
investor_idstringqueryInvestor external id (usr_…).
statusstringqueryList mode only.
updated_sincestringqueryISO 8601 timestamp; switches to sync mode. Mutually exclusive with cursor (cursor wins).
cursorstringqueryOpaque cursor from a previous response's meta.next_cursor.
per_pageintegerqueryRecords per page, 1–100 (default 25). Sync pages count distinct investments.
Responses
curl https://api.wefunder.com/api/v2/investments?company_id=value&offering_id=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "string",
"visible": true,
"status": "reserved",
"converted_to": "string",
"converted_from": "string",
"offering": "string",
"company": "string",
"investment_type": "string",
"offering_type": "string",
"group": "string",
"applied_at": "string",
"amounts": {
"committed_cents": 123,
"investment_size_cents": 123,
"in_escrow_cents": 123,
"raised_cents": 123,
"currency": "usd"
},
"shares": "295",
"average_share_price": "3.38",
"needs_whitelisting": true,
"external_username": "string",
"message": "string",
"investor": {
"id": "string",
"deactivated": true,
"via_entity": true,
"name": "string",
"legal_name": "string",
"email": "string",
"address": null,
"bio": "string"
},
"blockers": [
{
"key": "string",
"description": "string"
}
],
"contracts": [
{
"name": "string",
"override_amount_cents": 123,
"early_bird": true
}
],
"observed_at": "string",
"cursor": "string",
"reason": "changed"
}
],
"meta": {
"mode": "bootstrap",
"has_more": true,
"next_cursor": "string",
"page_count": 123,
"published_through": "string"
}
}/investments/{id}Retrieve an investment (current)
The same record shape as the list, derived now from the investment rather than read
from published state, so an investor who just acted sees the change at once. Available
for any investment in the token's audience: the user's own (any status) or a
founder-visible investment on a company the user edits. meta.published_matches says
whether the published record already agrees; the sync stream converges within its
interval.
Parameters
idstringrequiredpathInvestment external id (inv_…).
Responses
curl https://api.wefunder.com/api/v2/investments/{id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"visible": true,
"status": "reserved",
"converted_to": "string",
"converted_from": "string",
"offering": "string",
"company": "string",
"investment_type": "string",
"offering_type": "string",
"group": "string",
"applied_at": "string",
"amounts": {
"committed_cents": 123,
"investment_size_cents": 123,
"in_escrow_cents": 123,
"raised_cents": 123,
"currency": "usd"
},
"shares": "295",
"average_share_price": "3.38",
"needs_whitelisting": true,
"external_username": "string",
"message": "string",
"investor": {
"id": "string",
"deactivated": true,
"via_entity": true,
"name": "string",
"legal_name": "string",
"email": "string",
"address": null,
"bio": "string"
},
"blockers": [
{
"key": "string",
"description": "string"
}
],
"contracts": [
{
"name": "string",
"override_amount_cents": 123,
"early_bird": true
}
],
"observed_at": "string",
"cursor": "string",
"reason": "changed"
},
"meta": {
"source": "current",
"published_observed_at": "string",
"published_matches": true
}
}/offerings/{offering_id}/statsInvestment totals for an offering
Count and committed amount of the founder-visible published records for one offering,
by status, from the same rows GET /investments?offering_id=… lists, so the two
reconcile. These are not the public campaign figures (the progress bar has its own
rules and sources); they are the sum of the records you can list. Requires the token's
user to edit the offering's company.
Parameters
offering_idstringrequiredpathOffering external id (ofr_…).
Responses
curl https://api.wefunder.com/api/v2/offerings/{offering_id}/stats \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"offering": "string",
"company": "string",
"currency": "string",
"by_status": null,
"total": {
"count": 123,
"committed_cents": 123,
"raised_cents": 123
}
},
"meta": {
"source": "published",
"published_through": "string"
}
}Investment Delta
/companies/{company_id}/investments/changesLegacy alias: bootstrap or page investment changes for a company
Compatibility alias. This path keeps working unchanged for partners already on it,
but new integrations should use List or sync investments
(GET /investments?company_id=…): same records, interchangeable cursors. The
migration notes
list the differences.
The Investment Delta API: keep a copy of a company's investment records in sync by
polling. Call without cursor to bootstrap (list every current record for the
company); every response carries meta.next_cursor; call again with that cursor to
receive only the records whose published state changed since. Records are the same
shape in both modes.
- Records are published state, not live rows: Wefunder publishes a record when the investment's founder-visible state changes, and serves exactly what was published.
visible: falserecords are tombstones: the investment is no longer visible to the company (canceled, converted to another round, hidden, or deleted). Delete your copy.- Apply records in
cursororder.observed_atis when the payload was observed, not a version; a record you read late carries the current published state. - 410 Gone means your cursor predates the 90-day retention window. Bootstrap again and replace your dataset for the company from the result (records absent from the bootstrap are deleted).
- Investor identity fields (
investor.name,investor.legal_name,investor.email,investor.address,investor.bio,message,external_username) are omitted unless the token carriesread:investors:pii. - Money is integer minor units plus
amounts.currency(committed_cents,investment_size_cents,in_escrow_cents,contracts[].override_amount_cents).sharesandaverage_share_priceare decimal strings,nullon rounds without shares.amounts.raised_centsis the row's contribution to the public raised figure (0 whileneeds_whitelisting); sum it, notcommitted_cents, to match the deal page.
Parameters
company_idstringrequiredpathThe company's external id (co_…).
cursorstringqueryOpaque cursor from a previous response's meta.next_cursor. Omit to bootstrap.
per_pageintegerqueryRecords per page, 1–100 (default 25). Delta pages count distinct investments.
Responses
curl https://api.wefunder.com/api/v2/companies/{company_id}/investments/changes?cursor=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "string",
"visible": true,
"status": "reserved",
"converted_to": "string",
"converted_from": "string",
"offering": "string",
"company": "string",
"investment_type": "string",
"offering_type": "string",
"group": "string",
"applied_at": "string",
"amounts": {
"committed_cents": 123,
"investment_size_cents": 123,
"in_escrow_cents": 123,
"raised_cents": 123,
"currency": "usd"
},
"shares": "295",
"average_share_price": "3.38",
"needs_whitelisting": true,
"external_username": "string",
"message": "string",
"investor": {
"id": "string",
"deactivated": true,
"via_entity": true,
"name": "string",
"legal_name": "string",
"email": "string",
"address": null,
"bio": "string"
},
"blockers": [
{
"key": "string",
"description": "string"
}
],
"contracts": [
{
"name": "string",
"override_amount_cents": 123,
"early_bird": true
}
],
"observed_at": "string",
"cursor": "string",
"reason": "changed"
}
],
"meta": {
"mode": "bootstrap",
"has_more": true,
"next_cursor": "string",
"page_count": 123,
"company_id": "string"
}
}Portfolio
/portfolioGet portfolio summary
Returns totals across the authenticated investor's portfolio: cost basis,
current value, realized and unrealized gains, and per-status position counts.
Accepts the same status and company filters as GET /portfolio/positions
to total a slice of the portfolio, such as only exited positions.
Requires a user-authorized token. App-only (client credentials) tokens receive 403.
Portfolio values are recalculated periodically rather than on each request,
so recent investments and valuation changes can take a few minutes to appear.
as_of is the timestamp of the oldest calculation included in the response.
Monetary values are integer cents; per-share prices and return multiples are decimal strings.
Parameters
statusstringqueryTotal only positions with this status.
companystringqueryTotal only positions in this company, by its id (co_...). Unknown ids return 404.
Responses
curl https://api.wefunder.com/api/v2/portfolio?status=value&company=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"type": "portfolio_summary",
"attributes": {
"currency": "usd",
"other_currencies": [],
"total_cost_basis_cents": 123,
"total_current_value_cents": 123,
"total_unrealized_gain_cents": 123,
"total_realized_gain_cents": 123,
"return_multiple": "1.3107",
"position_counts": {
"active": 123,
"exited": 123,
"sold": 123,
"failed": 123
},
"as_of": "string"
}
}
}/portfolio/positionsList portfolio positions
Returns the authenticated investor's positions, one per offering
(fundraise), newest first. Position totals cover everything the investor
holds in that offering; securities breaks the total down by security
offering and legal owner, so early bird tiers and personally-held vs
entity-held stakes each appear separately. Fund and SPV positions identify
the companies the vehicle invested in under holdings.
Mind the units when deriving an average cost per share: cost_basis_cents
is integer cents, while shares_held, current_share_price and
terms.share_price are decimal strings in major units of the position's
currency. Use decimal arithmetic and divide the cents by 100 first:
cost_basis_cents / 100 / shares_held. For example, 215000 cents over
"200.0" shares is 1075 cents per share, or 10.75 USD per share, which is
what to compare with a current_share_price of "14.4632". Dividing
cost_basis_cents by shares_held without the / 100 yields cents per
share, 100 times the prices shown. When shares_held is null or zero (a
non-share security, or a valuation that is not per-share) there is no
average cost per share: report it as unavailable instead of treating the
missing share count as a number.
Requires a user-authorized token, like GET /portfolio.
Parameters
stringper_pageintegerqueryPage size, 1-100. Defaults to 25.
statusstringqueryFilter positions by status.
companystringqueryFilter to a single company by its id (co_...). Unknown ids return 404.
Responses
curl https://api.wefunder.com/api/v2/portfolio/positions?per_page=value&status=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "ofr_9aKxQ2vF8mNp1zT5wY7Qb3Cd",
"type": "portfolio_position",
"attributes": {
"offering_id": "ofr_9aKxQ2vF8mNp1zT5wY7Qb3Cd",
"company": {
"id": "co_2bt9eJn6X8C9gnShl63qlzkK",
"name": "Acme Robotics",
"slug": "acme-robotics",
"url": "https://wefunder.com/acme-robotics"
},
"asset_type": "company",
"security": null,
"status": "active",
"exit_reason": "ipo",
"exited_on": "2026-08-15",
"invested_at": "string",
"currency": "usd",
"cost_basis_cents": 123,
"current_value_cents": 123,
"unrealized_gain_cents": 123,
"realized_gain_cents": 123,
"return_multiple": "1.6492",
"shares_held": "string",
"current_share_price": "string",
"securities": [
{
"security": null,
"early_bird": true,
"terms": {
"share_price": "10.0",
"currency": "usd",
"note_cap_cents": 123,
"uncapped": false,
"note_discount": "20.0",
"premoney_valuation_cents": 123
},
"cost_basis_cents": 123,
"current_value_cents": 123,
"unrealized_gain_cents": 123,
"realized_gain_cents": 123,
"shares_held": "string",
"current_share_price": "string",
"invested_at": "string",
"owner": {
"kind": "individual",
"name": "string"
},
"investor_count": 123
}
],
"holdings": [
{
"company": {
"id": "co_2bt9eJn6X8C9gnShl63qlzkK",
"name": "Acme Robotics",
"slug": "acme-robotics",
"url": "https://wefunder.com/acme-robotics"
},
"status": "active"
}
],
"investor_count": 123,
"as_of": "string"
}
}
],
"meta": {
"has_more": true,
"page_count": 123,
"next_cursor": 123
}
}Campaigns
/campaignsList founder campaigns
Retrieves all fundraising campaigns for companies where the authenticated user is a founder. This endpoint returns comprehensive campaign data including funding progress, investor counts, and campaign status.
Use this endpoint to:
- Build custom founder dashboards
- Monitor fundraising progress across multiple campaigns
- Generate reports on campaign performance
- Integrate campaign data into your own tools
Only founders with the appropriate permissions can access this endpoint. The response includes both active and closed campaigns, with detailed metrics for each.
Parameters
stringResponses
curl https://api.wefunder.com/api/v2/campaigns \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "ofr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"type": "campaign",
"attributes": {
"state": "active",
"company_id": 101,
"company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"company_name": "My Startup Inc.",
"company_url": "my-startup-inc",
"created_at": "2023-01-10T09:00:00Z",
"updated_at": "2023-03-15T14:30:00Z",
"closed_at": "2023-06-30T23:59:59Z",
"amount_raised": 25000,
"investor_count": 42
}
}
],
"meta": {
"page_count": 25,
"has_more": true,
"next_cursor": 12345
}
}Syndicates
/syndicatesList syndicates
Returns syndicates the authenticated user can manage, based on their roles. Results can be filtered by status and sorted by name or creation date.
Parameters
cursorstringqueryOpaque cursor from the previous response's meta.next_cursor.
per_pageintegerqueryResults per page, 1-100. Defaults to 25.
Responses
curl https://api.wefunder.com/api/v2/syndicates?cursor=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "syn_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"type": "syndicate",
"attributes": {
"name": "Acme Syndicate",
"slug": "acme-syndicate",
"tagline": "Investing in the future of AI",
"description": "Example text",
"avatar_url": "https://uploads.wefunder.com/uploads/club/icon/42/large_avatar.png",
"published": true,
"launched": true,
"membership_open": true,
"syndicate_type": "string",
"auto_accept_accredited_members": false,
"auto_approve_join_sessions": true,
"fund_required": false,
"annual_subscription": {
"fund_investment_amount": "string",
"deals_per_year": 123,
"amount_per_deal": "string"
},
"traditional_fund": {
"require_minimum_investment": true,
"minimum_investment_amount": "string"
},
"member_count": 47,
"deal_count": 3,
"primary_fund_company_id": 4242,
"primary_fund_company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"created_by_user_id": 123,
"created_by": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
],
"meta": {
"page_count": 25,
"has_more": true,
"next_cursor": 12345
}
}/syndicates/{syndicate_id}Get syndicate details
Returns full details for a specific syndicate including settings, team configuration, and summary metrics.
Parameters
stringResponses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "syn_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"type": "syndicate",
"attributes": {
"name": "Acme Syndicate",
"slug": "acme-syndicate",
"tagline": "Investing in the future of AI",
"description": "Example text",
"avatar_url": "https://uploads.wefunder.com/uploads/club/icon/42/large_avatar.png",
"published": true,
"launched": true,
"membership_open": true,
"syndicate_type": "string",
"auto_accept_accredited_members": false,
"auto_approve_join_sessions": true,
"fund_required": false,
"annual_subscription": {
"fund_investment_amount": "string",
"deals_per_year": 123,
"amount_per_deal": "string"
},
"traditional_fund": {
"require_minimum_investment": true,
"minimum_investment_amount": "string"
},
"member_count": 47,
"deal_count": 3,
"primary_fund_company_id": 4242,
"primary_fund_company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"created_by_user_id": 123,
"created_by": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}BetaUpdate syndicate settings
Update syndicate configuration. Currently supports name, description, and tagline.
Requires write:syndicates scope and at least operator permission.
Parameters
stringRequest Body
syndicateobjectrequiredResponses
curl -X PATCH https://api.wefunder.com/api/v2/syndicates/{syndicate_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'{
"data": {
"id": "syn_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"type": "syndicate",
"attributes": {
"name": "Acme Syndicate",
"slug": "acme-syndicate",
"tagline": "Investing in the future of AI",
"description": "Example text",
"avatar_url": "https://uploads.wefunder.com/uploads/club/icon/42/large_avatar.png",
"published": true,
"launched": true,
"membership_open": true,
"syndicate_type": "string",
"auto_accept_accredited_members": false,
"auto_approve_join_sessions": true,
"fund_required": false,
"annual_subscription": {
"fund_investment_amount": "string",
"deals_per_year": 123,
"amount_per_deal": "string"
},
"traditional_fund": {
"require_minimum_investment": true,
"minimum_investment_amount": "string"
},
"member_count": 47,
"deal_count": 3,
"primary_fund_company_id": 4242,
"primary_fund_company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"created_by_user_id": 123,
"created_by": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}Syndicate Members
/syndicates/{syndicate_id}/membersList members
Returns the member directory for a syndicate with role, status, tags, sidebar notes, and investment history summaries. Supports filtering, sorting, search, and pagination.
Parameters
stringrolestringqueryFilter by role (e.g. creator, manager, member, invitee, applicant)
permissionstringqueryFilter by syndicate permission level
searchstringquerySearch by name or email
sortstringquerySort order. investment_amount (highest total invested first) is moderator-only;
non-moderators requesting it get the default order. Unknown values fall back to the default.
has_investedstringqueryFilter by whether the member has invested in any syndicate deal
accreditedstringqueryModerator-only. Filter by accreditation status; ignored for non-moderators.
tagstringqueryFilter by 'can help with' tag (ILIKE match)
locationstringqueryMatch on city, state, or country (public location data only).
cursorstringqueryOpaque cursor from the previous response's meta.next_cursor.
per_pageintegerqueryResults per page, 1-100. Defaults to 25.
Responses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members?role=value&permission=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
],
"meta": {
"page_count": 25,
"has_more": true,
"next_cursor": 12345
}
}/syndicates/{syndicate_id}/members/inviteInvite member
Send an invitation to join the syndicate by email.
Parameters
stringRequest Body
emailstringrequirednamestringDisplay name for the invitee
syndicate_permissionstringPermission level. Only the syndicate creator can assign full_access (admin).
Responses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/invite \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"name": "string",
"syndicate_permission": "full_access"
}'{
"data": {
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/members/{member_id}Update member
Update title and carry override for a member. Requires operator permission.
Parameters
stringstringRequest Body
memberobjectrequiredResponses
curl -X PATCH https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'{
"data": {
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/members/{member_id}Remove member (requires intent)
Removing a member is irreversible and requires human approval through the Intent system.
This endpoint always returns 422 with a use_intents error directing you to
POST /intents with action syndicates.remove_member.
Parameters
stringstringResponses
curl -X DELETE https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"/syndicates/{syndicate_id}/members/{member_id}/approveApprove applicant
Approve a pending applicant. Only applicants can be approved via API; invitees must accept their invite link.
Parameters
stringstringResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id}/approve \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/members/{member_id}/hideExile member
Exile (hide) a member from the syndicate. Sets their role to exiled.
Parameters
stringstringResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id}/hide \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/members/{member_id}/promotePromote member to admin
Promote a member to full_access (admin) role. Only the syndicate creator can promote members.
Parameters
stringstringResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id}/promote \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/members/{member_id}/demoteDemote member to operator
Demote a member from full_access (admin) to operator permission.
Parameters
stringstringResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id}/demote \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/members/{member_id}/restoreRestore exiled or resigned member
Restore a member who was previously exiled or resigned. Sets their role back to member.
Parameters
stringstringResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id}/restore \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "mem_3StSZhDjMHzn8NzEkX0kgEuN",
"type": "syndicate_member",
"attributes": {
"user_id": 123,
"user": "usr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"role": "member",
"invite_role": "admin",
"syndicate_permission": "full_access",
"title": "Example title",
"sort_order": 5,
"carry_percentage_override": 20,
"carry_discount_percentage": 0,
"management_fee_discount_percentage": 0,
"public_on_syndicate_profile": true,
"interests": [
"string"
],
"stage_preferences": [
"string"
],
"looking_for": [
"string"
],
"linkedin_url": "string",
"twitter_url": "string",
"website": "string",
"state": "string",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"bio": "Example text",
"city": "San Francisco",
"country": "US",
"last_activity_at": "2025-03-01T12:00:00Z",
"profile_url": "/janedoe",
"tags": [
"Fundraising",
"Product Strategy"
],
"joined_at": "2025-03-01T12:00:00Z",
"investment_total": "5000",
"deal_count": 2,
"accredited": true,
"legal_name": "Example Name",
"starred": true,
"private_tags": [
"VIP",
"Follow up"
],
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/members/{member_id}/resend_inviteResend invitation
Parameters
stringstringResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id}/resend_invite \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"/syndicates/{syndicate_id}/members/reorderReorder members
Set the display order for the member directory.
Parameters
stringRequest Body
member_idsarrayrequiredMember ids as returned by the list endpoint (mem_…), in the desired display order. Unknown ids return 404 and change nothing.
Responses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/reorder \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"member_ids": [
"mem_8Kd0aB3xQ9k2",
"mem_vF8mNp1zT5wY",
"mem_2Lq7cR4sX0bE"
]
}'/syndicates/{syndicate_id}/members/export_csvExport members CSV
Generate a CSV export of the member directory. Returns the CSV data directly with Content-Type text/csv. Requires operator permission.
Parameters
stringResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/export_csv \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"/syndicates/{syndicate_id}/join_sessionsBetaCreate a join session
Mint a hosted join session that turns an invitee into a member of a
syndicate you manage. The session is bound to one email; the recipient
completes the join on wefunder.com/join/session/{id}, and you learn the
outcome by polling this session or via join_session.* webhooks.
Requires write:syndicate_members (included in write:syndicates),
operator permission, and an active installation of your app on the
syndicate. Phase 1 supports mode: hosted only.
Parameters
stringRequest Body
join_sessionobjectrequiredResponses
curl -X POST https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/join_sessions \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/syndicates/{syndicate_id}/join_sessionsBetaList join sessions
List the join sessions your app's installation minted on this syndicate. Sessions are install-scoped: you only see the ones your own install created.
Parameters
stringcursorstringqueryOpaque cursor from the previous response's meta.next_cursor.
per_pageintegerqueryResults per page, 1-100. Defaults to 25.
Responses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/join_sessions?cursor=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"/syndicates/{syndicate_id}/join_sessions/{id}BetaGet a join session
Fetch one join session your app's installation minted on this syndicate,
by its js_ id. Poll this to learn the session's current status.
Parameters
stringidstringrequiredpathThe join session's js_ id.
Responses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/join_sessions/{id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"/syndicates/{syndicate_id}/members/{member_id}/investmentsList member investments
Returns this member's investments in syndicate deals. Scoped to the syndicate's selected deals (one per company, matching directory semantics). Moderator-only.
amount and meta.total_amount are whole dollars as strings.
Parameters
stringstringResponses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/members/{member_id}/investments \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "inv_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"type": "member_investment",
"attributes": {
"fundraise_id": 75496,
"offering": "ofr_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"company_name": "Substack",
"amount": "5000",
"status": "confirmed",
"created_at": "2025-03-01T12:00:00Z"
}
}
],
"meta": {
"count": 123,
"total_amount": "8000"
}
}Syndicate Deals
/syndicates/{syndicate_id}/dealsList deals
Returns the syndicate's live deals (open, oversubscribed, or closing) with status,
terms, and metrics. Closed and upcoming rounds are not listed; statistics.total_deals
counts the same visible deal set in every state. The visible set is every round of the
syndicate's directory companies except invite-only companies' rounds and
testing-the-waters rounds; a syndicate with no directory companies falls back to its
explicitly linked rounds, excluding invite-only companies' rounds only.
Parameters
stringcursorstringqueryOpaque cursor from the previous response's meta.next_cursor.
per_pageintegerqueryResults per page, 1-100. Defaults to 25.
Responses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/deals?cursor=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "ofr_yw3OhusvpfJP4Pk3wRYV1F2R",
"type": "syndicate_deal",
"attributes": {
"name": "Acme Corp Series A",
"status": "open",
"company_name": "Acme Corp",
"company_id": 1234,
"company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"company_url": "acme-corp",
"company_logo_url": "https://uploads.wefunder.com/uploads/company/logo/1234/large_logo.png",
"amount_raised": "230000",
"investor_count": 47,
"funding_target": "50000000",
"exemption": null,
"security": null,
"min_investment": "100",
"max_investment": "50000",
"description": "Example text",
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z",
"closed_at": "2025-03-01T12:00:00Z",
"funding_started_at": "2025-03-01T12:00:00Z"
}
}
],
"meta": {
"page_count": 25,
"has_more": true,
"next_cursor": 12345
}
}/syndicates/{syndicate_id}/deals/{fundraise_id}Get deal details
Returns full details for a specific deal including investor breakdown.
Parameters
stringstringResponses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/deals/{fundraise_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "ofr_yw3OhusvpfJP4Pk3wRYV1F2R",
"type": "syndicate_deal",
"attributes": {
"name": "Acme Corp Series A",
"status": "open",
"company_name": "Acme Corp",
"company_id": 1234,
"company": "co_8Kd0aB3xQ9k2vF8mNp1zT5wY",
"company_url": "acme-corp",
"company_logo_url": "https://uploads.wefunder.com/uploads/company/logo/1234/large_logo.png",
"amount_raised": "230000",
"investor_count": 47,
"funding_target": "50000000",
"exemption": null,
"security": null,
"min_investment": "100",
"max_investment": "50000",
"description": "Example text",
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z",
"closed_at": "2025-03-01T12:00:00Z",
"funding_started_at": "2025-03-01T12:00:00Z"
}
}
}/syndicates/{syndicate_id}/deals/{fundraise_id}/investorsList deal investors
Returns syndicate members who invested in this deal. Results are scoped to syndicate member user IDs only and sorted by amount descending.
Manager/operator only. Who invested how much is moderator data, as on the
web deal pipeline page: an ordinary member, backer, or follower of the syndicate
gets 403, even with read:syndicates. Callers who pass that gate see
user_email.
amount is whole dollars as a string (e.g. "5000" is $5,000).
Offset-paginated: pass offset and per_page; meta carries total_count,
offset, per_page, and has_more. Without per_page the full list is returned.
Parameters
stringstringoffsetintegerqueryNumber of investors to skip.
per_pageintegerqueryResults per page, 1-200. Omit to return every investor.
Responses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/deals/{fundraise_id}/investors?offset=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "usr_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"type": "deal_investor",
"attributes": {
"user_id": 456,
"user": "usr_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"user_name": "Jane Smith",
"user_email": "[email protected]",
"avatar_url": "https://uploads.wefunder.com/uploads/user/avatar/456/large_photo.jpg",
"amount": "5000",
"status": "confirmed",
"invested_at": "2025-03-01T12:00:00Z"
}
}
],
"meta": {
"count": 123,
"total_count": 123,
"offset": 123,
"per_page": 123,
"has_more": true
}
}Syndicate Statistics
/syndicates/{syndicate_id}/statisticsGet syndicate statistics
Returns aggregate metrics for a syndicate including member counts, deal counts, total raised, and recent activity.
total_raised and total_investors are computed from directory-selected deals
(one per directory company: its live round, else its most recent successful round).
total_deals counts the syndicate's visible deal set in every state (the rounds
GET /syndicates/{syndicate_id}/deals draws from, which excludes invite-only
companies' rounds and testing-the-waters rounds of directory companies);
live_deals is the live subset of it, the rows that endpoint lists.
total_raised is whole dollars as a string.
Parameters
stringResponses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/statistics \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"type": "syndicate_statistics",
"attributes": {
"total_members": 45,
"members_by_role": {
"manager": 3,
"member": 35,
"invitee": 5,
"creator": 1,
"applicant": 1
},
"total_deals": 3,
"live_deals": 1,
"total_raised": "107800",
"total_investors": 6527,
"recent_activity_count": 4
}
}
}Syndicate Portfolio
/syndicates/{syndicate_id}/portfolioGet syndicate portfolio summary
Returns totals across the syndicate's portfolio: cost basis, current value,
gains, per-status deal counts, and the number of distinct investors.
Accepts the same status and company filters as the positions endpoint
to total a slice of the portfolio, such as only exited deals.
The summary covers the syndicate's funded deals, summed across everyone holding their securities (not just current members), as aggregate figures only. Member-level data is available on the members endpoints.
Portfolio values are recalculated periodically rather than on each request,
so recent investments and valuation changes can take a few minutes to appear.
as_of is the timestamp of the oldest calculation included in the response.
Monetary values are integer cents; per-share prices and return multiples are decimal strings.
Parameters
stringstatusstringqueryTotal only deals with this status.
companystringqueryTotal only positions in this company, by its id (co_...). Unknown ids return 404.
Responses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/portfolio?status=value&company=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"type": "syndicate_portfolio_summary",
"attributes": {
"currency": "usd",
"other_currencies": [],
"total_cost_basis_cents": 123,
"total_current_value_cents": 123,
"total_unrealized_gain_cents": 123,
"total_realized_gain_cents": 123,
"return_multiple": "string",
"deal_counts": {
"active": 123,
"exited": 123,
"sold": 123,
"failed": 123
},
"investor_count": 123,
"as_of": "string"
}
}
}/syndicates/{syndicate_id}/portfolio/positionsList syndicate portfolio positions
Returns the syndicate's portfolio one deal at a time, newest first. Each
position is one fundraise ("offering"), aggregated across everyone holding
its securities, with investor_count at both the position and security
level.
securities breaks each position down by security offering (for example,
an early bird tier vs the regular terms) — most deals have a single entry.
Fund and SPV deals identify the companies the vehicle invested in under
holdings; some older vehicles have no recorded holdings and return an
empty array.
Parameters
stringstringper_pageintegerqueryPage size, 1-100. Defaults to 25.
statusstringqueryFilter positions by status.
companystringqueryFilter to a single company by its id (co_...). Unknown ids return 404.
Responses
curl https://api.wefunder.com/api/v2/syndicates/{syndicate_id}/portfolio/positions?per_page=value&status=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "ofr_9aKxQ2vF8mNp1zT5wY7Qb3Cd",
"type": "portfolio_position",
"attributes": {
"offering_id": "ofr_9aKxQ2vF8mNp1zT5wY7Qb3Cd",
"company": {
"id": "co_2bt9eJn6X8C9gnShl63qlzkK",
"name": "Acme Robotics",
"slug": "acme-robotics",
"url": "https://wefunder.com/acme-robotics"
},
"asset_type": "company",
"security": null,
"status": "active",
"exit_reason": "ipo",
"exited_on": "2026-08-15",
"invested_at": "string",
"currency": "usd",
"cost_basis_cents": 123,
"current_value_cents": 123,
"unrealized_gain_cents": 123,
"realized_gain_cents": 123,
"return_multiple": "1.6492",
"shares_held": "string",
"current_share_price": "string",
"securities": [
{
"security": null,
"early_bird": true,
"terms": {
"share_price": "10.0",
"currency": "usd",
"note_cap_cents": 123,
"uncapped": false,
"note_discount": "20.0",
"premoney_valuation_cents": 123
},
"cost_basis_cents": 123,
"current_value_cents": 123,
"unrealized_gain_cents": 123,
"realized_gain_cents": 123,
"shares_held": "string",
"current_share_price": "string",
"invested_at": "string",
"owner": {
"kind": "individual",
"name": "string"
},
"investor_count": 123
}
],
"holdings": [
{
"company": {
"id": "co_2bt9eJn6X8C9gnShl63qlzkK",
"name": "Acme Robotics",
"slug": "acme-robotics",
"url": "https://wefunder.com/acme-robotics"
},
"status": "active"
}
],
"investor_count": 123,
"as_of": "string"
}
}
],
"meta": {
"has_more": true,
"page_count": 123,
"next_cursor": 123
}
}Intents
/intents/previewPreview an intent without proposing it
Runs every check POST /intents runs — the action's feature flag, resource type and id,
token binding, who may propose, and the handler's own validation — and returns what the
reviewer would read, without minting anything. The draft step for agents: admitted by any
proposing scope or read:explore, and the action's own scope is not required on the
token, so a user can shape the text before granting the write permission. The caller must
still be allowed to propose on the resource, and for a syndicate-owned token the application's
Installation scope ceiling still applies (an install granted only read:syndicates cannot
preview a write:syndicates action: 403 insufficient_scope). Same request body as
POST /intents (without idempotency_key). Errors are the same as POST /intents would give.
Request Body
action_namestringrequiredresource_typestringrequiredresource_idstringrequiredparamsobjectResponses
curl -X POST https://api.wefunder.com/api/v2/intents/preview \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action_name": "string",
"resource_type": "string",
"resource_id": "string"
}'{
"data": {
"type": "intent_preview",
"attributes": {
"action": "string",
"resource_type": "string",
"resource_id": "string",
"params": null,
"impact_summary": "string",
"scope": "string"
}
}
}/intentsPropose an intent
Propose a dangerous or irreversible action for human approval. Returns a review_url
where a human must review the impact and approve before the action executes.
The entity that proposes an intent can never approve it. Approval always happens on Wefunder's UI by a user with permission on the resource.
Each action names the scope that may propose it and the resource type it targets
(syndicates.* → write:syndicates on a syndicate; comments.create → write:comments
on a Company). The token must hold that action's scope; holding another proposing scope
is not enough (403 insufficient_scope).
comments.create posts a question on a company's Ask tab, or an answer to one, as the
requesting user once they approve on wefunder.com. resource_id is the company (co_...);
params is { target_type: "company" | "comment", target: "co_..." | "cmt_...", body, disclosure_key? } (disclosure_key ∈ investor, stockholder, promoter, financial_stakeholder).
Who may post is the site's own rule: anyone the page is available to may ask (unless the
company has closed questions); only the company's team may answer. Only the requester can
approve. 20 proposals per user per day (429).
An idempotency_key names one operation. Reusing it for the same operation returns the
existing intent (200) while that intent is pending, approved, executing, or executed;
reusing it for a different action, resource, or params is a 409 idempotency_conflict.
An action still rolling out per account returns 403 feature_disabled for a user who is
not yet enabled. POST /intents/preview runs the same checks without minting.
syndicates.close_deal and syndicates.finalize_deal were removed in 2026-10-15: on this
version they answer 400 bad_request ("Unknown action") with details.removed_in_version.
A syndicate's managers close and finalize deals on wefunder.com. Intents minted before
still appear in GET /intents with those action names.
See Intents documentation for the full pattern.
Request Body
action_namestringrequiredThe action to perform
resource_typestringrequiredThe resource type the action targets, as the action table names it; the example is the syndicate type.
resource_idstringrequiredThe resource's id in the API's vocabulary — the syndicate's syn_... for a syndicates.* action.
paramsobjectAction-specific parameters
idempotency_keystringClient-provided key naming this one operation. While an intent with this key is pending, approved, executing, or executed, the same operation returns it (200); a different operation under the same key is a 409.
requested_by_agentstringHuman-readable name of the agent proposing the action
Responses
curl -X POST https://api.wefunder.com/api/v2/intents \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action_name": "syndicates.remove_member",
"resource_type": "Club",
"resource_id": "syn_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"params": {
"member_id": "mem_7Hk2mP9qR4sT1uV6wX8yZ3aB"
},
"idempotency_key": "remove-mem_7Hk2mP9qR4sT1uV6wX8yZ3aB-2026-10",
"requested_by_agent": "Claude via MCP"
}'{
"data": {
"id": "int_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"type": "intent",
"attributes": {
"action": "syndicates.remove_member",
"status": "pending",
"resource_type": "Club",
"resource_id": "syn_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"impact_summary": "Remove Jane Smith from Acme Syndicate. She will lose access to the syndicate's deals.",
"review_url": "https://wefunder.com/intents/a1b2c3d4-e5f6-7890-abcd-ef1234567890/review",
"requested_by_agent": "Claude via MCP",
"expires_at": "2025-03-01T12:00:00Z",
"approved_at": "2025-03-01T12:00:00Z",
"executed_at": "2025-03-01T12:00:00Z",
"rejection_reason": "Example text",
"execution_result": null,
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}/intentsList intents
List intents created by the current token, optionally filtered by status or resource.
Parameters
statusstringqueryresource_typestringqueryresource_idstringqueryFor Club resources, the syndicate's id (syn_...).
cursorstringqueryOpaque cursor from the previous response's meta.next_cursor.
per_pageintegerqueryResponses
curl https://api.wefunder.com/api/v2/intents?status=value&resource_type=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "int_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"type": "intent",
"attributes": {
"action": "syndicates.remove_member",
"status": "pending",
"resource_type": "Club",
"resource_id": "syn_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"impact_summary": "Remove Jane Smith from Acme Syndicate. She will lose access to the syndicate's deals.",
"review_url": "https://wefunder.com/intents/a1b2c3d4-e5f6-7890-abcd-ef1234567890/review",
"requested_by_agent": "Claude via MCP",
"expires_at": "2025-03-01T12:00:00Z",
"approved_at": "2025-03-01T12:00:00Z",
"executed_at": "2025-03-01T12:00:00Z",
"rejection_reason": "Example text",
"execution_result": null,
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
],
"meta": {
"page_count": 25,
"has_more": true,
"next_cursor": 12345
}
}/intents/{intent_id}Get intent status
Check the current status of an intent. Use this to poll for approval
after proposing an intent, or subscribe to intent.* webhook events instead.
Parameters
intent_idstringrequiredpathThe intent's id (int_...), as returned when the intent was minted (data.id / meta.*_intent.id). The legacy UUID form is still accepted.
Responses
curl https://api.wefunder.com/api/v2/intents/int_aB3xQ9k2vF8mNp1zT5wY7Qc4 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "int_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"type": "intent",
"attributes": {
"action": "syndicates.remove_member",
"status": "pending",
"resource_type": "Club",
"resource_id": "syn_aB3xQ9k2vF8mNp1zT5wY7Qc4",
"impact_summary": "Remove Jane Smith from Acme Syndicate. She will lose access to the syndicate's deals.",
"review_url": "https://wefunder.com/intents/a1b2c3d4-e5f6-7890-abcd-ef1234567890/review",
"requested_by_agent": "Claude via MCP",
"expires_at": "2025-03-01T12:00:00Z",
"approved_at": "2025-03-01T12:00:00Z",
"executed_at": "2025-03-01T12:00:00Z",
"rejection_reason": "Example text",
"execution_result": null,
"created_at": "2025-03-01T12:00:00Z",
"updated_at": "2025-03-01T12:00:00Z"
}
}
}Activity
/connected-appsList connected apps
Returns all OAuth apps the user has authorized, with summary stats.
Responses
curl https://api.wefunder.com/api/v2/connected-apps \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": 123,
"type": "connected_app",
"attributes": {
"name": "ChatGPT via Wefunder MCP",
"scopes": [
"read:syndicates",
"write:syndicates"
],
"last_active_at": "2025-03-01T12:00:00Z",
"action_count": 34,
"created_at": "2025-03-01T12:00:00Z"
}
}
]
}/connected-apps/{app_id}Revoke connected app
Revoke all tokens for this app. Any pending intents from this app are automatically expired.
Parameters
app_idintegerrequiredpathResponses
curl -X DELETE https://api.wefunder.com/api/v2/connected-apps/{app_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"revoked": true,
"tokens_revoked": 2
}
}Referral Codes
/referral_codesBetaList referral codes
The referral codes your application created, newest first. A referral code records that a
visitor arrived through your link (?wfr=ref_…); it never changes what the visitor sees and
grants no access. Filter with active=true or active=false.
Every referral code operation takes your application's own server key (a
client_credentials token). A user or installation token gets 403 app_credentials_required.
Parameters
activebooleanquerystringper_pageintegerqueryResponses
curl https://api.wefunder.com/api/v2/referral_codes?active=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "ref_8f3ExampleReferral0000",
"type": "referral_code",
"attributes": {
"label": "October newsletter",
"active": true,
"target": {
"type": "company",
"id": "co_7hQExampleCompany0001",
"unavailable": true
},
"utm": {
"source": "acme_newsletter",
"medium": "email",
"campaign": "october",
"content": "header_link",
"term": "seed_round"
},
"metadata": null,
"link_parameter": "wfr=ref_8f3ExampleReferral0000",
"stats": null,
"created_at": "2026-10-13T17:30:00Z",
"updated_at": "2026-10-13T17:30:00Z"
}
}
],
"meta": {
"has_more": false,
"page_count": 1,
"next_cursor": 123,
"active_limit": 500,
"request_id": "string"
}
}/referral_codesBetaCreate a referral code
Mints a referral code for your application. No relationship with the company is needed.
Put it on any wefunder.com link as ?wfr=<id>.
Before its first code, your organization must accept the referral attribution terms once:
Wefunder does not pay partners per referral, and a partner may not be compensated per
referral unless it is a registered broker-dealer. Until an owner or admin accepts them in
the developer portal, this returns 422 attribution_terms_required with
details.acceptance_url.
An application may have at most 500 active codes (422 quota_exceeded); deactivate codes
you no longer use. UTM presets fill blank utm_* fields on visits that carry the code. A
source or campaign starting with wf_ is reserved for Wefunder's own channels and
returns 422 reserved_utm_prefix. Idempotency keys are not supported here: a retried
request may create a second code, which you can deactivate.
Request Body
labelstringrequiredYour name for the code, e.g. a campaign or newsletter issue.
company_idstringCredit only investments in this company (co_…). Omit both company_id and
offering_id for a code that credits any company. Fixed at creation.
offering_idstringCredit only investments in this offering's company (ofr_…). The offering must
be publicly visible. Fixed at creation.
utmobjectmetadataobjectFree-form metadata for your own use, at most 4 KB.
Responses
curl -X POST https://api.wefunder.com/api/v2/referral_codes \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "October newsletter",
"company_id": "co_7hQExampleCompany0001",
"offering_id": "ofr_7hQExampleOffering01"
}'{
"data": {
"id": "ref_8f3ExampleReferral0000",
"type": "referral_code",
"attributes": {
"label": "October newsletter",
"active": true,
"target": {
"type": "company",
"id": "co_7hQExampleCompany0001",
"unavailable": true
},
"utm": {
"source": "acme_newsletter",
"medium": "email",
"campaign": "october",
"content": "header_link",
"term": "seed_round"
},
"metadata": null,
"link_parameter": "wfr=ref_8f3ExampleReferral0000",
"stats": null,
"created_at": "2026-10-13T17:30:00Z",
"updated_at": "2026-10-13T17:30:00Z"
}
},
"meta": {
"request_id": "string"
}
}/referral_codes/{id}BetaRetrieve a referral code
Responses
curl https://api.wefunder.com/api/v2/referral_codes/{id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "ref_8f3ExampleReferral0000",
"type": "referral_code",
"attributes": {
"label": "October newsletter",
"active": true,
"target": {
"type": "company",
"id": "co_7hQExampleCompany0001",
"unavailable": true
},
"utm": {
"source": "acme_newsletter",
"medium": "email",
"campaign": "october",
"content": "header_link",
"term": "seed_round"
},
"metadata": null,
"link_parameter": "wfr=ref_8f3ExampleReferral0000",
"stats": null,
"created_at": "2026-10-13T17:30:00Z",
"updated_at": "2026-10-13T17:30:00Z"
}
},
"meta": {
"request_id": "string"
}
}/referral_codes/{id}BetaUpdate a referral code
Changes the label, pauses or resumes the code (active), or replaces its UTM presets. The
target is fixed at creation. A paused code is ignored on arrival; existing cookies still
credit investments for up to 30 days. Reactivating counts against the 500 active codes.
Request Body
labelstringactivebooleanutmobjectResponses
curl -X PATCH https://api.wefunder.com/api/v2/referral_codes/{id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "string",
"active": true
}'{
"data": {
"id": "ref_8f3ExampleReferral0000",
"type": "referral_code",
"attributes": {
"label": "October newsletter",
"active": true,
"target": {
"type": "company",
"id": "co_7hQExampleCompany0001",
"unavailable": true
},
"utm": {
"source": "acme_newsletter",
"medium": "email",
"campaign": "october",
"content": "header_link",
"term": "seed_round"
},
"metadata": null,
"link_parameter": "wfr=ref_8f3ExampleReferral0000",
"stats": null,
"created_at": "2026-10-13T17:30:00Z",
"updated_at": "2026-10-13T17:30:00Z"
}
},
"meta": {
"request_id": "string"
}
}/referral_codes/{id}/statsBetaReferral code stats
What your code produced, per company. Your access to each company decides what you see:
- Counts (any app): for each company in the code's scope, one cell per ISO week (Monday
to Sunday, UTC) with the unique investors referred that week as a range,
{min, max}. Ranges are never exact, currently of width 3 and starting at zero, so{0, 2}also means none. Each week is published once, early on the following Monday, and never revised; the current week has no cell. There are no totals across weeks or companies, and no amounts. - Rows (your app is installed on the company with
read:attribution:anonymized, or at founder tier withread:attribution:full): that company's referred investments instead of ranges, anonymized or in full.
A targeted code's scope is its target; an untargeted code's scope is every company its
visitors landed on. visits and unique_visitors are a daily snapshot up to the end of
visits_as_of (UTC). Paginated over companies; each company's weekly series is complete.
Parameters
stringcompany_idstringqueryOnly this company (co_…). Use it with investments_cursor to page an installed company's rows.
investments_cursorintegerqueryWith company_id, the investments_next_cursor from the previous page of that company's rows.
per_pageintegerqueryResponses
curl https://api.wefunder.com/api/v2/referral_codes/{id}/stats?company_id=value&investments_cursor=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "ref_8f3ExampleReferral0000",
"type": "referral_code_stats",
"attributes": null
},
"meta": {
"has_more": false,
"page_count": 1,
"next_cursor": 123,
"request_id": "string"
}
}Installations
/installationsList installations of your app
Where the calling application is installed. Someone who manages the app's organization sees every install; anyone else sees the installs they made or could revoke. Revoked installs stay listed for 30 days.
Responses
curl https://api.wefunder.com/api/v2/installations \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "string",
"type": "installation",
"attributes": {
"target": {
"type": "company",
"id": "string",
"name": "string"
},
"tier": "string",
"scopes": [
"string"
],
"status": "active",
"installed_at": "string",
"installed_by": "string",
"revoked_at": "string"
}
}
],
"meta": {
"count": 123
}
}/installationsInstall your app on a company or syndicate
Installs the calling application on a company or syndicate the token's user can edit (or, for a syndicate, manages), and mints the company-owned token the install stands for. The token appears in this response only. Requires a token authorized by a user.
The install is granted at the caller's tier (founder, admin or editor for a company). An
editor-tier install carries read scopes only; write scopes in scopes are dropped. Installing
on a company outside your own organization requires the app to be approved.
Request Body
target_typestringrequiredtarget_idstringrequiredThe company (co_…) or syndicate (syn_…) external id.
scopesarraySubset of the app's declared scopes to grant. Defaults to all of them.
tierstringOptional higher tier (founder / full_access), honored only when the caller holds it.
Responses
curl -X POST https://api.wefunder.com/api/v2/installations \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"target_type": "company",
"target_id": "string",
"scopes": [],
"tier": "string"
}'{
"data": {
"id": "string",
"type": "installation",
"attributes": {
"target": {
"type": "company",
"id": "string",
"name": "string"
},
"tier": "string",
"scopes": [
"string"
],
"status": "active",
"installed_at": "string",
"installed_by": "string",
"revoked_at": "string"
}
},
"token": {
"access_token": "at_live_…",
"token_type": "Bearer",
"scope": "string",
"installation": "string",
"created_at": 123
},
"meta": null
}/installations/eligibleList where you can install your app
Companies the token's user can edit and syndicates they manage, with the tier an install would be granted at and the current install if one exists. Requires a token authorized by a user.
Parameters
target_typestringqueryResponses
curl https://api.wefunder.com/api/v2/installations/eligible?target_type=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"type": "company",
"id": "string",
"name": "string",
"tier": "string",
"installed": true,
"installation": null
}
],
"meta": null
}/installations/{external_id}Retrieve an installation
Responses
curl https://api.wefunder.com/api/v2/installations/{external_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "installation",
"attributes": {
"target": {
"type": "company",
"id": "string",
"name": "string"
},
"tier": "string",
"scopes": [
"string"
],
"status": "active",
"installed_at": "string",
"installed_by": "string",
"revoked_at": "string"
}
},
"meta": null
}/installations/{external_id}Revoke an installation
Revokes the install and every token issued for it. Requires a token authorized by a user who can edit the company (or manages the syndicate), or who administers the app's organization.
Responses
curl -X DELETE https://api.wefunder.com/api/v2/installations/{external_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "installation",
"attributes": {
"target": {
"type": "company",
"id": "string",
"name": "string"
},
"tier": "string",
"scopes": [
"string"
],
"status": "active",
"installed_at": "string",
"installed_by": "string",
"revoked_at": "string"
}
},
"meta": null
}/installations/{external_id}/tokensMint a token for an installation
Mints another company-owned token for an active install — for example one a founder made through the install link. Scopes default to the install's grant and can only narrow it. The token appears in this response only. Requires a token authorized by a user who installed it, could revoke it, or manages the app's organization.
Parameters
external_idstringrequiredpathRequest Body
scopesarrayResponses
curl -X POST https://api.wefunder.com/api/v2/installations/{external_id}/tokens \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scopes": []
}'{
"data": {
"id": "string",
"type": "installation",
"attributes": {
"target": {
"type": "company",
"id": "string",
"name": "string"
},
"tier": "string",
"scopes": [
"string"
],
"status": "active",
"installed_at": "string",
"installed_by": "string",
"revoked_at": "string"
}
},
"token": {
"access_token": "at_live_…",
"token_type": "Bearer",
"scope": "string",
"installation": "string",
"created_at": 123
},
"meta": null
}Webhook Endpoints
/webhook_endpointsList webhook endpoints
Your application's webhook endpoints. The signing secret is never included. Requires an owner, admin, or developer role in the application's organization.
Responses
curl https://api.wefunder.com/api/v2/webhook_endpoints \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "whe_8f3ExampleEndpoint00",
"type": "webhook_endpoint",
"attributes": {
"url": "string",
"url_hint": "hooks.zapier.com …3kq9Zz",
"installation": "inst_7hQExampleInstall01",
"mode": "live",
"events": [
"string"
],
"enabled": true,
"secret": "whsec_4Zb7ExampleSigningSecret0000000000",
"failing_since": "string",
"last_delivery_at": "string",
"last_delivery_status": "200",
"created_at": "string"
}
}
],
"meta": {
"count": 123,
"quota": 123,
"request_id": "string"
}
}/webhook_endpointsCreate a webhook endpoint
Registers an endpoint for your application. The response is the only time the
signing secret is returned; store it to verify signatures. Requires an
owner, admin, or developer role in the application's organization.
On the sandbox API this returns 403 manage_endpoints_on_live_api: create test
endpoints through the live API with mode: "test", and they are mirrored into sandbox.
Request Body
urlstringrequiredPublic HTTPS URL to receive deliveries (private/internal IPs rejected).
installationstringBind the endpoint to one active installation of your app (inst_…) instead of
creating an app-wide endpoint. An unknown or revoked id is 404. An installation token
may omit this (it always binds to its own installation); a user token may bind only to
an installation its holder has a role on at or above the installation's granted tier.
Bound endpoints are live-only, capped at 5 per installation, idempotent on
(installation, url, mode), and their url is returned only in this response.
eventsarrayrequiredEvent names to subscribe to (from the event catalog). At least one.
modestringResponses
curl -X POST https://api.wefunder.com/api/v2/webhook_endpoints \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/wefunder",
"installation": "inst_7hQExampleInstall01",
"events": [
"offering.opened",
"investment.executed"
],
"mode": "live"
}'{
"data": {
"id": "whe_8f3ExampleEndpoint00",
"type": "webhook_endpoint",
"attributes": {
"url": "string",
"url_hint": "hooks.zapier.com …3kq9Zz",
"installation": "inst_7hQExampleInstall01",
"mode": "live",
"events": [
"string"
],
"enabled": true,
"secret": "whsec_4Zb7ExampleSigningSecret0000000000",
"failing_since": "string",
"last_delivery_at": "string",
"last_delivery_status": "200",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}/webhook_endpoints/{external_id}Get a webhook endpoint
Requires an owner, admin, or developer role in the application's organization.
Parameters
stringResponses
curl https://api.wefunder.com/api/v2/webhook_endpoints/{external_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "whe_8f3ExampleEndpoint00",
"type": "webhook_endpoint",
"attributes": {
"url": "string",
"url_hint": "hooks.zapier.com …3kq9Zz",
"installation": "inst_7hQExampleInstall01",
"mode": "live",
"events": [
"string"
],
"enabled": true,
"secret": "whsec_4Zb7ExampleSigningSecret0000000000",
"failing_since": "string",
"last_delivery_at": "string",
"last_delivery_status": "200",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}/webhook_endpoints/{external_id}Update a webhook endpoint
events replaces the subscription list wholesale (no merge); omit it to leave it
unchanged. An endpoint must subscribe to at least one event, so [] and null are
rejected; delete the endpoint to stop all deliveries. Requires an org management role.
Returns 403 manage_endpoints_on_live_api on the sandbox API; use the live API.
Parameters
stringRequest Body
urlstringeventsarrayResponses
curl -X PATCH https://api.wefunder.com/api/v2/webhook_endpoints/{external_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "string",
"events": []
}'{
"data": {
"id": "whe_8f3ExampleEndpoint00",
"type": "webhook_endpoint",
"attributes": {
"url": "string",
"url_hint": "hooks.zapier.com …3kq9Zz",
"installation": "inst_7hQExampleInstall01",
"mode": "live",
"events": [
"string"
],
"enabled": true,
"secret": "whsec_4Zb7ExampleSigningSecret0000000000",
"failing_since": "string",
"last_delivery_at": "string",
"last_delivery_status": "200",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}/webhook_endpoints/{external_id}Remove a webhook endpoint
Stops deliveries immediately. The endpoint is retained as removed and cannot be restored.
Returns 403 manage_endpoints_on_live_api on the sandbox API; use the live API.
Parameters
stringResponses
curl -X DELETE https://api.wefunder.com/api/v2/webhook_endpoints/{external_id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "string",
"type": "webhook_endpoint",
"removed": true
}
}/webhook_endpoints/{external_id}/rotate_secretRotate the signing secret
Returns a new signing secret (shown once). The previous secret keeps signing for a
24h overlap window, so deliveries carry a v1 for both; verify against either.
Returns 403 manage_endpoints_on_live_api on the sandbox API; use the live API.
Parameters
stringResponses
curl -X POST https://api.wefunder.com/api/v2/webhook_endpoints/{external_id}/rotate_secret \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "whe_8f3ExampleEndpoint00",
"type": "webhook_endpoint",
"attributes": {
"url": "string",
"url_hint": "hooks.zapier.com …3kq9Zz",
"installation": "inst_7hQExampleInstall01",
"mode": "live",
"events": [
"string"
],
"enabled": true,
"secret": "whsec_4Zb7ExampleSigningSecret0000000000",
"failing_since": "string",
"last_delivery_at": "string",
"last_delivery_status": "200",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}/webhook_endpoints/{external_id}/reenableRe-enable a disabled endpoint
Recovery after auto-disable. Idempotent. Requires an org management role on the live API. Also allowed on the sandbox API for an endpoint sandbox itself disabled (sandbox runs its own health checks on its mirror of a test endpoint), authorized by the caller's realm.
Parameters
stringResponses
curl -X POST https://api.wefunder.com/api/v2/webhook_endpoints/{external_id}/reenable \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "whe_8f3ExampleEndpoint00",
"type": "webhook_endpoint",
"attributes": {
"url": "string",
"url_hint": "hooks.zapier.com …3kq9Zz",
"installation": "inst_7hQExampleInstall01",
"mode": "live",
"events": [
"string"
],
"enabled": true,
"secret": "whsec_4Zb7ExampleSigningSecret0000000000",
"failing_since": "string",
"last_delivery_at": "string",
"last_delivery_status": "200",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}/webhook_endpoints/{external_id}/testSend a test event
Sends a real, signed example event (fake values) using the production envelope,
signature scheme, and transport, and reports the outcome inline. Does not affect
delivery health. Rate-limited to 10 per minute per endpoint. Investor email appears
in the example only if your application holds read:investors:pii, matching what
real deliveries can carry.
Parameters
stringRequest Body
eventstringEvent to simulate. Defaults to the endpoint's first subscribed event.
Responses
curl -X POST https://api.wefunder.com/api/v2/webhook_endpoints/{external_id}/test \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event": "investment.created"
}'{
"data": {
"type": "webhook_test",
"delivered": true,
"response_code": 123,
"error": "timeout",
"duration_ms": 123,
"event": "string",
"payload": null
},
"meta": {
"request_id": "string"
}
}Member Links
/offerings/{id}/member_linksList member links
The member links your install minted on this offering, newest first.
Another app installed on the same offering never sees them, and they never
appear in /invite_links. Requires a syndicate- or company-owned token of an
app installed on the offering's syndicate or company.
Parameters
stringstringResponses
curl https://api.wefunder.com/api/v2/offerings/{id}/member_links \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "il_8kQm2xVb7nRt4WcY9pLe3HdA",
"type": "member_link",
"attributes": {
"url": "https://wefunder.com/arc-hockey?invite_token=kL273wxd4DGb896V87ddtLE9",
"state": "created",
"reference": "member_8812",
"wefunder_user_id": "usr_4fQ8sLm2Vx9TbR7nKc3YdHpW",
"investment_id": "inv_7hTk2PqW9mXc4RbN8vLs3DyF",
"offering": "ofr_2nVb8KxQ4tLm9RcW7pHs3FdY",
"created_at": "string"
}
}
],
"meta": {
"has_more": true,
"page_count": 123,
"request_id": "string",
"next_cursor": "string"
}
}/offerings/{id}/member_linksCreate a member link
Mints a link that sends one of your members to this offering's deal page. It
carries no email: it binds to the first Wefunder account that invests through
it, whatever address that account uses, or up front when you pass the
wefunder_user_id of a member whose account you already know. A bound link
answers only to its account: anyone else (logged out, or another account) gets
no private access and no invited pricing, and is asked to sign in with the
invited account.
The member gets what an invitation from the offering's manager or founder gets: access to a private round and invited pricing.
Pass reference (your member id) to make the create idempotent per offering:
repeating it returns the live link with 200. The same reference on another
offering mints that offering's own link, since a member gets one link per
deal. Requires a syndicate- or company-owned token of an app installed on the
offering's syndicate or company; user tokens get 404.
Parameters
stringstringRequest Body
member_linkobjectResponses
curl -X POST https://api.wefunder.com/api/v2/offerings/{id}/member_links \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'{
"data": {
"id": "il_8kQm2xVb7nRt4WcY9pLe3HdA",
"type": "member_link",
"attributes": {
"url": "https://wefunder.com/arc-hockey?invite_token=kL273wxd4DGb896V87ddtLE9",
"state": "created",
"reference": "member_8812",
"wefunder_user_id": "usr_4fQ8sLm2Vx9TbR7nKc3YdHpW",
"investment_id": "inv_7hTk2PqW9mXc4RbN8vLs3DyF",
"offering": "ofr_2nVb8KxQ4tLm9RcW7pHs3FdY",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}/member_links/{id}Get a member link
A member link your install minted, with its live state. Links minted by
another app answer 404.
Parameters
stringResponses
curl https://api.wefunder.com/api/v2/member_links/{id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "il_8kQm2xVb7nRt4WcY9pLe3HdA",
"type": "member_link",
"attributes": {
"url": "https://wefunder.com/arc-hockey?invite_token=kL273wxd4DGb896V87ddtLE9",
"state": "created",
"reference": "member_8812",
"wefunder_user_id": "usr_4fQ8sLm2Vx9TbR7nKc3YdHpW",
"investment_id": "inv_7hTk2PqW9mXc4RbN8vLs3DyF",
"offering": "ofr_2nVb8KxQ4tLm9RcW7pHs3FdY",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}/member_links/{id}/cancelCancel a member link
Retracts the invitation. Idempotent. The link grants nothing new afterwards: a checkout started after the cancel, including the same member's next investment, is priced at standard terms. Investments already made through the link keep the terms they were made at. A link nobody invested through is also released from the account you pre-bound it to. Revoking your install cancels every member link it minted that no investment went through (same release); links an investment went through stand.
Parameters
stringResponses
curl -X POST https://api.wefunder.com/api/v2/member_links/{id}/cancel \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "il_8kQm2xVb7nRt4WcY9pLe3HdA",
"type": "member_link",
"attributes": {
"url": "https://wefunder.com/arc-hockey?invite_token=kL273wxd4DGb896V87ddtLE9",
"state": "created",
"reference": "member_8812",
"wefunder_user_id": "usr_4fQ8sLm2Vx9TbR7nKc3YdHpW",
"investment_id": "inv_7hTk2PqW9mXc4RbN8vLs3DyF",
"offering": "ofr_2nVb8KxQ4tLm9RcW7pHs3FdY",
"created_at": "string"
}
},
"meta": {
"request_id": "string"
}
}Partner Invites & Sessions
/offerings/{id}/investment_sessionsBetaList investment sessions
Lists the investment sessions your app created on this offering, newest first;
filter by status. A session belongs to the application that created it: no other
app sees it, even one of your organization. A syndicate- or company-owned token sees
only its own syndicate's or company's sessions. An offering with none of your app's
sessions lists nothing, so the id reveals nothing about the offering.
Parameters
stringstatusstringqueryOnly sessions in this state
per_pageintegerqueryPage size (default 25, max 100)
stringResponses
curl https://api.wefunder.com/api/v2/offerings/{id}/investment_sessions?status=value&per_page=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "is_abc123",
"type": "investment_session",
"attributes": {
"status": "pending",
"url": "https://wefunder.com/invest/session/is_abc123",
"spv_id": "spv_abc123",
"email": "[email protected]",
"allocation_cents": 5000000,
"kyc_status": "pending",
"funding_status": "pending",
"investment_id": "invt_def789",
"metadata": null,
"created_at": "2025-01-15T10:00:00Z",
"expires_at": "string",
"events": [
{
"id": "evt_abc123",
"event": "investment_session.completed",
"occurred_at": "string"
}
]
}
}
],
"meta": {
"has_more": true,
"page_count": 123,
"request_id": "string",
"next_cursor": 123
}
}/offerings/{id}/investment_sessionsBetaCreate an investment session
Canonical path: the offering comes from the URL, so spv_id may be
omitted from the body (if sent it must match, else 422 offering_mismatch).
Authorized for any offering the caller may act on (an install on its
syndicate or company, a role on it, or created by your app).
Creates a single-use, recipient-specific hosted investment session (analogous to
a Stripe Checkout Session) on the SPV named by spv_id in the body. The session
walks one investor through accreditation, document signing, and payment, and
produces a durable Investment on success. Returns a url the recipient opens
to begin. If the recipient already has an active session on the SPV, that
session is returned instead of creating a duplicate; if another app holds
that recipient's active session there, the create is refused with 409
session_conflict (a recipient has one active session per offering).
Parameters
stringstringRequest Body
investment_sessionobjectrequiredResponses
curl -X POST https://api.wefunder.com/api/v2/offerings/{id}/investment_sessions \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'{
"data": {
"id": "is_abc123",
"type": "investment_session",
"attributes": {
"status": "pending",
"url": "https://wefunder.com/invest/session/is_abc123",
"spv_id": "spv_abc123",
"email": "[email protected]",
"allocation_cents": 5000000,
"kyc_status": "pending",
"funding_status": "pending",
"investment_id": "invt_def789",
"metadata": null,
"created_at": "2025-01-15T10:00:00Z",
"expires_at": "string",
"events": [
{
"id": "evt_abc123",
"event": "investment_session.completed",
"occurred_at": "string"
}
]
}
},
"meta": {
"request_id": "string"
}
}/investment_sessionsBetaList investment sessions
Alias of /partner/investment_sessions (#23636).
Lists the investment sessions your app created, newest first. A session belongs
to the application that created it: no other app sees it, even one of your
organization. A syndicate- or company-owned token sees only its own syndicate's or
company's sessions. Creating a session needs authority on the offering; reading or
canceling one you created does not.
Filter by spv_id and/or status.
Parameters
spv_idstringqueryOnly sessions on this SPV
statusstringqueryOnly sessions in this state
per_pageintegerqueryPage size (default 25, max 100)
stringResponses
curl https://api.wefunder.com/api/v2/investment_sessions?spv_id=value&status=value \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": [
{
"id": "is_abc123",
"type": "investment_session",
"attributes": {
"status": "pending",
"url": "https://wefunder.com/invest/session/is_abc123",
"spv_id": "spv_abc123",
"email": "[email protected]",
"allocation_cents": 5000000,
"kyc_status": "pending",
"funding_status": "pending",
"investment_id": "invt_def789",
"metadata": null,
"created_at": "2025-01-15T10:00:00Z",
"expires_at": "string",
"events": [
{
"id": "evt_abc123",
"event": "investment_session.completed",
"occurred_at": "string"
}
]
}
}
],
"meta": {
"has_more": true,
"page_count": 123,
"request_id": "string",
"next_cursor": 123
}
}/investment_sessions/{id}BetaGet an investment session
Alias of /partner/investment_sessions (#23636).
Returns the full session including an events timeline of durable platform
events recorded about it.
Parameters
idstringrequiredpathThe investment session ID (prefixed, e.g. is_abc123)
Responses
curl https://api.wefunder.com/api/v2/investment_sessions/is_abc123 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "is_abc123",
"type": "investment_session",
"attributes": {
"status": "pending",
"url": "https://wefunder.com/invest/session/is_abc123",
"spv_id": "spv_abc123",
"email": "[email protected]",
"allocation_cents": 5000000,
"kyc_status": "pending",
"funding_status": "pending",
"investment_id": "invt_def789",
"metadata": null,
"created_at": "2025-01-15T10:00:00Z",
"expires_at": "string",
"events": [
{
"id": "evt_abc123",
"event": "investment_session.completed",
"occurred_at": "string"
}
]
}
},
"meta": {
"request_id": "string"
}
}/investment_sessions/{id}BetaCancel an investment session
Alias of /partner/investment_sessions (#23636).
Cancels a session so its link stops working. Valid while the session is
pending, in_progress, or abandoned; repeating the call on an
already-canceled session returns the same 200. A completed or expired
session cannot be canceled (422 session_not_cancelable).
Parameters
idstringrequiredpathThe investment session ID (prefixed, e.g. is_abc123)
Responses
curl -X DELETE https://api.wefunder.com/api/v2/investment_sessions/is_abc123 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"{
"data": {
"id": "is_abc123",
"type": "investment_session",
"attributes": {
"status": "pending",
"url": "https://wefunder.com/invest/session/is_abc123",
"spv_id": "spv_abc123",
"email": "[email protected]",
"allocation_cents": 5000000,
"kyc_status": "pending",
"funding_status": "pending",
"investment_id": "invt_def789",
"metadata": null,
"created_at": "2025-01-15T10:00:00Z",
"expires_at": "string",
"events": [
{
"id": "evt_abc123",
"event": "investment_session.completed",
"occurred_at": "string"
}
]
}
},
"meta": {
"request_id": "string"
}
}