Skip to main content

Changelog

Changes to the public API, newest first. Each entry names the stability tier of the surface it touches. Only a breaking change creates a new dated API version; see Versioning.

2026-10-16 · Publishable keys read the public catalog; money as integer cents​

Added​

  • Publishable key as a bearer (GA). Your app's client id (pk_live_… / pk_test_…) now works directly as the Authorization: Bearer credential on every read:public operation: GET /explore, GET /offerings/{id}, GET /companies/{id}, GET /companies/search. No token mint, no secret, so it may be sent from a browser or a phone. It reaches public reads only (anything else is 403 insufficient_scope), follows the key's mode, and is refused for an archived key or a disabled app exactly like a token. Rate-limited per key at 300 requests per 5 minutes on top of the per-IP buckets. GET requests answer cross-origin from any origin, so a page on any domain can make these reads with no domain registration; writes keep the redirect-URI origin policy. See Authentication.
  • Integer cents on company and offering money (GA). amount_raised_cents, funding_target_cents, max_funding_target_cents and min_investment_cents on GET /explore and GET /offerings/{id}; amount_raised_cents and funding_target_cents on current_raise, amount_raised_cents on past_rounds[] and wefunder_rounds[], and *_cents twins of every totals field on GET /companies/{id}. Integers, the GET /investments convention.

Deprecated​

  • The dollar-string money fields those cents fields sit beside (amount_raised, funding_target, max_funding_target, min_investment, profile_total_raised, profile_reported_off_platform, raised_on_wefunder_all_time). They keep returning on every current dated version and are removed in the next one. A string can carry a fraction ("642300.5"); the integer field is exact.

Changed​

  • Client-credentials tokens now live 24 hours (was 2). The per-client token-endpoint limit is 60 per hour (was 20). User and installation tokens are unchanged.

2026-10-15 · Join sessions and investment sessions reach beta​

Changed​

  • Syndicate join sessions (POST/GET /syndicates/{id}/join_sessions, GET .../{id}) and hosted investment sessions (/offerings/{id}/investment_sessions, GET/DELETE /investment_sessions/{id}, GET /investment_sessions) move from preview to beta. They now appear in the public API reference. Additive, so every API version serves them.
  • write:syndicate_members and read:investment_sessions / write:investment_sessions are selectable when you create an app. write:syndicates already includes write:syndicate_members, so existing syndicate apps need no change. The legacy /partner/investment_sessions aliases stay in preview.

2026-10-15 · New API version 2026-10-15​

A new dated version. Applications created before today are pinned to 2026-10-01 and see no change until they move their pin; new applications are pinned to 2026-10-15. Send Wefunder-Version: 2026-10-15 on a request to try it without moving your pin. To upgrade, check your integration for calls to the three operations and two intent actions below; if it makes none, move your pin. Nothing else changed.

Removed​

  • GET /activity (GA). Returns 404 not_found with details.removed_in_version: {/* lint-doc-paths: ignore */} "2026-10-15" on this version. The /activity name is reserved for the activity feed; the audit trail of what an app did stays visible to the user in Settings → Activity on wefunder.com.
  • POST /syndicates/{id}/deals/{fundraise_id}/close and .../finalize (Beta). Same 404. Closing and finalizing a deal is done by the syndicate's managers on wefunder.com.
  • The syndicates.close_deal and syndicates.finalize_deal intent actions. POST /intents and POST /intents/preview answer 400 bad_request ("Unknown action") with details.removed_in_version: "2026-10-15". Intents minted earlier keep their action names in GET /intents.

Each removed operation runs its version check before authorization, so it reads as absent for every caller on 2026-10-15, whatever the token's scopes.

Changed​

  • A user token acts on a company's offerings (invite links, investment sessions, partner SPVs) only when its person has edit access to the company, the rule wefunder.com applies to invite links. A founder or admin listed on the company without edit access now gets 404, as for an offering the token cannot reach, including on an SPV your app created. Syndicate managers and install tokens are unchanged, and other users of your app still reach the SPVs it created.
  • A founder or admin without edit access to a company now installs your app read-only: POST /installations and the consent screen drop write: scopes, and a request for write scopes alone is 422 no_grantable_scopes.

2026-10-14 · Partner SPV create and read routes removed (preview)​

Removed​

  • The /partner/spvs routes that create, list and read SPVs are gone. All were preview operations, outside the versioned contract, so this needs no new API version. Use the replacements:
    • POST /partner/spvs → POST /syndicates/{id}/deals, with the same body under deal (Creating SPVs), then GET /syndicates/{id}/deals/{fundraise_id}/readiness for what the draft still needs.
    • GET /partner/spvs and GET /partner/spvs/{id} → GET /syndicates/{id}/deals and GET /syndicates/{id}/deals/{fundraise_id} once the deal is published to the syndicate.
    • GET /partner/spvs/{id}/status → the status on the deal, the SPV body that /close and /cancel return, and the offering.* webhook events.
    • GET /partner/spvs/{id}/investments and GET /partner/spvs/{id}/investors → GET /syndicates/{id}/deals/{fundraise_id}/investors.
    • /partner/spvs/{id}/invite_links (list, create, get, update, cancel, resend, bulk) → /offerings/{id}/invite_links, the same endpoints at their canonical path.
  • POST /partner/spvs/{id}/close and POST /partner/spvs/{id}/cancel are unchanged (preview). /partner/investment_sessions is unchanged; /offerings/{id}/investment_sessions is its canonical path.

2026-10-14 · Followed companies: profile-only grants see the public list (GA)​

Changed​

  • GET /users/me/follows for a token whose only follows access comes from read:profile or write:profile now leaves out companies that asked not to be promoted (promotion_opt_in false), matching the follow list on the user's public Wefunder profile. A token holding write:follows, read:mcp (or the retired read:follows) still gets every company the user follows. The filter runs before paging, so it never shortens a page, and page_count counts the rows returned.

Added​

  • exited_on on GET /portfolio/positions and GET /syndicates/{syndicate_id}/portfolio/positions: the date an exited or failed position ended. Null for older exits recorded before Wefunder kept exit dates, even when exit_reason is set.
  • company.url on every position and fund holding: the company's page on wefunder.com, which is the attribution link target.
  • uncapped in each securities[].terms: true or false for a SAFE or convertible note, null for securities that never carry a cap.

Changed​

  • securities[].terms now follows the same rules as an offering's security.terms: a discount recorded as zero returns note_discount: null (it was "0.0"), and a cap recorded as zero returns note_cap_cents: null with uncapped: true (it was 0). Both fields were already nullable; non-zero values are unchanged.

2026-10-14 · Legacy Attribution API removed (internal)​

Removed​

  • The four legacy Attribution reads deprecated on 2026-10-13 (the attribution profile, the attribution campaign list, and per-campaign attribution stats and investments) now answer 410 Gone. They were internal-tier operations, outside the versioned contract, and no request reached them in the weeks before removal. Use referral codes instead.

2026-10-13 · Referral codes (beta)​

Added​

  • Referral codes, for partners that send people to Wefunder and want to know how many invested. Create codes with your app's server key (POST /referral_codes), add one to any wefunder.com link as ?wfr=ref_…, and read GET /referral_codes/{id}/stats: per company, one weekly range of unique investors ({min, max}, currently 3 wide, published early each Monday and never revised). If a founder installs your app with an attribution scope, you get that company's investments as rows instead. Rename, pause, or change UTM presets with PATCH /referral_codes/{id}.
  • New scopes read:referral_codes and write:referral_codes, self-serve in the portal. They are held by a client_credentials token only; a user or installation token is refused with 403 app_credentials_required. Your organization accepts the referral terms once before its first code (422 attribution_terms_required). Guide: Measure the Investors You Refer.

Deprecated​

  • GET /attribution/me, GET /attribution/campaigns, GET /campaigns/{id}/attribution/stats, and GET /campaigns/{id}/attribution/investments. They keep working for now; new integrations should use referral codes.

2026-10-13 · Partner SPVs: deals your app is installed on (Preview)​

Changed​

  • /partner/spvs list, get, status, investments, investors, close and cancel now work on any deal your app may act on: a deal of a syndicate or a round of a company your app is installed on, a deal the token's user manages, or an SPV your organization created through the API. The list takes syndicate and company filters. metadata is returned only to the organization that wrote it. See SPVs.
  • Opening a deal moved to wefunder.com, where the manager signs the deal's Listing Agreement (and Tax Service Agreement, when needed) first. POST /partner/spvs/{id}/open is no longer part of the preview.

2026-10-12 · Closed rounds on /explore (GA)​

Added​

  • GET /explore takes status: live (the default, unchanged), closed (rounds that finished raising, newest closed_at first), or all. Any other value is a 400. meta.status echoes it. See Closed rounds.
  • GET /explore honors per_page (default 25, max 100) like other list endpoints.

2026-10-07 · Installation webhook events (GA)​

Added​

  • Two webhook events for your app's own installations: installation.created fires when your app is installed on a company or syndicate or connected by a user, from any path; installation.revoked fires when an installation is revoked by the company or syndicate's admin, the user, your own team, or Wefunder. data carries the installation id, target, tier, granted scopes, timestamps, and the actor's role (never a name). installation.revoked goes to app-wide endpoints only, so prefer it to waiting for a 401 on a company token. See Events.

2026-10-06 · Attribution writes require write:attribution​

Security​

  • Every state-changing attribution call (POST /attribution/partners/register, creating or accepting partner invites, creating, approving or denying access requests, and creating, deleting, testing, re-keying or reactivating attribution webhook subscriptions) now requires the write:attribution scope in addition to its existing role and tier checks. The read:attribution:* scopes are read-only, as their names say; a token without write:attribution receives 403 insufficient_scope. Read endpoints are unchanged. Wefunder grants write:attribution to attribution partner apps with their read tiers; contact support if your integration writes and has not been granted it.

2026-10-06 · Investment sync contract corrections (GA)​

Fixed​

  • reason on investment sync records now documents recomputed, the value the API has emitted for derivation-only republishes since the webhook fields/first hints shipped; reprojected remains in the schema for rows published under the old name. Every reason is a record to upsert; only your notification rule may treat them differently.
  • A tombstone is documented as it is served: visible: false with id, observed_at, cursor and reason, and no payload fields. Tell it from your own canceled investment (a full record with visible: false and status: "canceled") by the absence of status, never by visible.
  • The sync examples carry their list filter (offering_id, company_id) on every continuation and delta request. The cursor is a ledger position and encodes no filters. Guide: Investments: list, sync, retrieve.

2026-10-05 · Syndicate membership departures​

Added​

  • Two webhook events for apps installed on a syndicate, under read:syndicates: syndicate_member.left (status: left, removed, or payment_failed) and syndicate_member.declined (status: declined or withdrawn). The shipped invited → applied → approved → joined events are unchanged. See Webhook events.

2026-10-01 · First released API version​

Added​

  • Dated versioning is live. Every request resolves a Wefunder-Version: the request header, else your application's pinned version, else the latest. Every response carries Wefunder-Version (the version that handled it) and Wefunder-Version-Latest. An unknown header value returns 400 invalid_request listing the valid versions. 2026-10-01 is the first released version; applications are pinned to it at creation. See Versioning.
  • 2025-01-15, the placeholder in pre-release docs and SDK builds, is accepted as an alias for 2026-10-01 during launch and will be removed. Pin new integrations to 2026-10-01.

2026-09-28 · Request ids and attribution on every response (GA)​

Changed​

  • Every response, including a 401 or 403 rejected before the request reached a controller, now carries X-Wf-Request-Id. The error body's request_id is the same req_… value, so one id finds the request in the developer portal's Logs tab and with support.
  • GET /companies/{id} and /companies/{id}/pitch render for a company's own editors even when no round is visible, matching the site's preview page.
  • Rounds limited to qualified purchasers (3(c)(7) funds) are shown only to viewers whose accreditation is qualified purchaser, across GET /explore, GET /offerings/{id}, and the company endpoints. Invite links do not bypass this.

2026-09-23 · Intent preview and comments.create (Beta)​

Added​

  • POST /intents/preview: run every check POST /intents runs and return the reviewer's impact_summary without minting an intent. Admitted by any proposing scope or read:explore.
  • Intent action comments.create (write:comments, resource Company): propose a question on a company's Ask tab or an answer to one; posted as the requester once they approve. Rolling out per account; a user who is not yet enabled receives 403 feature_disabled. Docs: Intents.

2026-09-23 · Public raised amount per investment (GA)​

Added​

  • amounts.raised_cents on every investment record: what the investment contributes to the offering's public raised figure. Equals investment_size_cents once soft-confirmed, 0 while the investment waits on its payment (needs_whitelisting). Summing it reproduces the deal page.
  • raised_cents on GET /offerings/{offering_id}/stats, per status and in total. Guide: Investments: list, sync, retrieve.

2026-09-23 · Syndicate membership webhooks (GA)​

Added​

  • Five webhook events for apps installed on a syndicate, under read:syndicates: syndicate_member.invited, syndicate_member.reinvited, syndicate_member.applied, syndicate_member.approved, and syndicate_member.joined. See Webhook events.

2026-09-22 · Shares on the investment record (GA)​

Added​

  • shares and average_share_price on every investment record: the shares this investment buys at its committed amount and the weighted average price per share, as decimal strings. Both null on rounds without shares (SAFE, note, reservation) or when no shares are computed. Every record republished once with reason: reprojected. Guide: Investments: list, sync, retrieve.

2026-09-17 · investment.changed webhook (GA)​

Added​

  • Webhook event investment.changed: one thin event per published change (investment id, visibility, company). Fetch the record from GET /investments/{id} or run a sync from your saved cursor. Requires read:investments. Docs: Webhook events.

2026-09-16 · Unified investments read model (GA)​

Added​

  • GET /investments: list, or sync with cursor / updated_since, the investment records the token may see: the companies its user edits plus the user's own investments. Filters company_id, offering_id, investor_id, status. meta.published_through on every page.
  • GET /investments/{id}: the same record derived now (current state), with meta.published_matches.
  • GET /offerings/{offering_id}/stats: totals by status over the records you can list.

Changed​

  • GET /investments previously returned the user's own investments in a legacy shape (decimal amount, raw state). It now returns the record shape above: status replaces state, amounts.committed_cents replaces amount.
  • GET /companies/{company_id}/investments/changes is now an alias of GET /investments?company_id=…. It keeps working unchanged and stays in the reference as a deprecated compatibility entry; new integrations should use GET /investments.

2026-09 · Company page gates (GA and Beta)​

Security​

  • GET /companies/{id} and its tabs (/pitch, /disclosures, /updates, /questions), the follow endpoints, and the search bar's profile_available flag now refuse a company exactly when wefunder.com would not render its page to the same person. Accredited-only companies need a soft-accredited read:explore viewer, and Vault companies without a Reg CF campaign need Vault access. A read:public key sees only what an anonymous visitor sees.

Fixed​

  • An uncapped SAFE or convertible note is valuation_cap: null with uncapped: true. Some rounds previously emitted "0", which read as a $0 valuation. uncapped is new on every terms object (offerings, syndicate deals, company rounds).

2026-09-21 · Installations (GA)​

Added​

  • Installations: install your app on a company or syndicate you manage, list where you can install, retrieve or revoke an installation, and mint an installation token. Docs: Installations.

2026-09-15 · Webhook endpoints (GA)​

Added​

  • /webhook_endpoints: create, update, and remove endpoints, rotate the signing secret, re-enable a disabled endpoint, and send a test event. Endpoints have a mode of live or test. Docs: Webhooks.

2026-06 · Explore API (GA)​

Added​

  • GET /explore and GET /offerings/{id}: the public offering catalog with sort and filter parameters, readable with read:public or, for the deals a specific user can see, read:explore. Guide: Build a deal aggregator.

2026-03 · Syndicate API, Intents, Activity​

Added​

  • Syndicate API (Beta): syndicates, members (list, invite, approve, promote, demote, hide, restore, reorder, export), deals (list, investors, close, finalize), statistics, and portfolio. Docs: Syndicate API.
  • Intents (GA): POST /intents proposes a write for human approval; GET /intents and GET /intents/{id} track it. Docs: Intents.
  • Activity (GA): GET /activity, plus connected-app listing and revocation. Docs: Activity.

2025-12 · Users and companies​

Added​

  • GET /users/me (GA), /users/me/companies, and follows on /users/me/follows (Beta).
  • GET /companies/{id} (GA) and company content: /companies/search, /pitch, /disclosures, /updates, /questions (Beta).
  • Investor portfolio: GET /portfolio and GET /portfolio/positions (Beta).

2025 · Foundation (GA)​

Added​

  • OAuth 2.0 with Authorization Code + PKCE (required) and Client Credentials (public scopes only). Prefixed credentials: pk_, sk_, at_, rt_, each _live_ or _test_.
  • Version-free URLs on https://api.wefunder.com with the Wefunder-Version header.
  • GET /campaigns and the Attribution API for marketing partners: /attribution/*, /campaigns/{id}/attribution/*, and attribution webhook subscriptions.
  • One error envelope everywhere: { "error": { "type", "message", "details", "request_id" } }.
  • Cursor pagination with meta.next_cursor and meta.has_more.
  • Per-org sandbox realms with seeded data and test credentials.
Partner SPV API

The Partner API (/partner/spvs, invite links, investment sessions, partner webhook subscriptions, sandbox simulators) is an invite-only preview and is not tracked here. Preview partners receive change notes directly.