Documentation
Concepts

Accounts and groups

Measure companies and workspaces, not only individual seats.

An account is the company or workspace a contact belongs to. Other tools call this a group. FounderHQ calls it an account, because it is also who pays.

Consumer product? You can skip this page. Contacts are enough.

Why accounts exist

If your product is sold to teams, one payment covers many seats. Tie that payment to a single contact and you credit the payer, ignore the teammate whose demo actually won the deal, and read $0 next to every other seat. An account fixes that: revenue and touches belong to the workspace.

Tell FounderHQ which account is active

founderhq.setAccount("workspace_123");
founderhq.setAccountProperties({ name: "Acme", seats: 12 });
founderhq.clearAccount();

Every event captured afterwards carries that account. On the web, the active account is per tab, so someone with two workspaces open in two tabs reports each correctly. On mobile, it is per app session.

When a sign-in changes both the person and the workspace, change them together:

founderhq.identify("user_8421", { email: "jane@acme.com" }, {
  account: "workspace_123",
});

Switching accounts does not restart the person's session. It rotates a separate account span, so your session metrics stay honest.

Name and picture

name names the account everywhere in FounderHQ. avatarUrl is its picture, such as the company's logo: the same property a contact's photo uses. Send a full https:// address.

founderhq.setAccountProperties({
  name: "Acme",
  avatarUrl: "https://cdn.acme.com/logo.png",
});

From your server, upsertAccount takes the same properties. Without a picture, FounderHQ draws the account's initials.

Declare membership from your server

The active account on an event is an observation. Your backend knows the truth: who joined, who left, and when. Only the Node SDK can say so.

events.accountMembership({
  account: "workspace_123",
  userId: "user_8421",
  state: "left",
  effectiveAt: new Date("2026-08-17T10:30:00Z"),
  idempotencyKey: "membership_user_8421_left_2026_08_17",
});
  • joined and left record real changes. A leave stops later activity from counting for that account.
  • retracted means the membership was wrong from the start. Do not use it when someone departs.
  • upsertAccount updates the account's own properties from the server.

How accounts change the numbers

  • A payment belongs to exactly one subject: a contact or an account. Never both, and never copied to each seat.
  • With Revenue owner set to Organization, a checkout that carries the account's context token goes to that account when the account is confirmed and the payer is a declared member of it at the time of the payment. A context token does not declare a membership: on a browser or app event it counts only for a payer your server already declared with accountMembership. Without the token, a payer in exactly one account pays for that account, and a payer in several accounts, or in none, pays as a contact. A goal that follows the revenue owner counts that contact's conversions for the contact. See Which account gets a payment.
  • Account attribution uses the touches of everyone who was a member at the time the money was earned. Touches from before the account existed still count, because visit → signup → create workspace → pay is the normal path.
  • If a person belongs to two accounts and browses without an active account, that touch counts for neither.
  • Bot traffic never creates membership and never counts as a touch.

AI agent or LLM? Read this page as markdown

On this page