Back to Blog

How to Model Companies and Workspaces in Your Email Platform

8 min read
How to Model Companies and Workspaces in Your Email Platform

Once your email platform supports account objects, the interesting question stops being "can I do this?" and becomes "what should I actually put in there?" It is easy to over-model. Teams mirror their entire organizations table, end up with 40 attributes, and then discover that half of them are stale and none of them are used in a segment.

Here is a framework for deciding what belongs in the account, what stays in your database, and how to name things so that a marketer six months from now can build a segment without asking an engineer.

The test: does it change an email?

Every candidate field gets one question. Does this change who receives an email, when they receive it, or what it says? If the answer is no to all three, leave it out.

That single filter kills most of the over-modeling instinct. Total lifetime API requests? Interesting for your dashboards, useless for routing an email. Signup source? Useful if you segment onboarding by it, dead weight if you do not.

FieldChanges an email?Verdict
planYes, gates upgrade and feature messagingSync
seatsYes, drives expansion nudgesSync
trialEndsAtYes, drives timingSync
mrrYes, segments high-value accountsSync
activeProjectsSometimes, if you email on adoptionMaybe
totalApiCallsNo, changes every minuteLeave out
billingAddressNoLeave out
internalCsmNotesNoLeave out

The four things worth syncing

1. Identity. Your own org id as the externalId, a name, and optionally a domain. Use your internal id, always. Names are not unique and change on rebrands. Domains are missing for personal-email signups and shared across subsidiaries. Your id is stable and makes every write idempotent:

{
  "externalId": "org_123",
  "name": "Acme",
  "domain": "acme.com",
  "attributes": { "plan": "pro", "seats": 12 }
}

2. Membership with roles. Which contacts belong to the account and what they can do. This is the part teams most often skip, and it is the part that makes role-targeted sends possible at all. Without roles, every account-level email is a broadcast to the whole team.

3. Three to five attributes. Sequenzy allows up to 100 attributes per account, and you should treat that as a guardrail rather than a goal. Start with the fields that appear in your actual segment conditions. You can add more the day you need them; you cannot easily discover which of your 40 attributes went stale.

4. Org-level events. trial_started, plan_changed, seat_limit_reached, payment_failed. These are things that happened to the company. Sending them as person events on whichever user happened to trigger the code path is how you end up emailing a junior engineer about a declined card.

What to leave in your own database

High-frequency counters. An attribute that changes every few seconds turns into a sync firehose and you will never build a segment on its exact value. If you need it, bucket it first: sync usageTier: "heavy" rather than eventsThisMonth: 418291.

Anything you would not want in an email. Internal risk scores, CSM notes, churn predictions. Attributes fan out to every member of the account, so treat everything you sync as potentially visible.

Derived state you can compute at send time. If daysUntilRenewal is just arithmetic on renewsAt, sync the date and do the math in the email.

Deep hierarchies. Parent orgs, sub-teams, nested workspaces. Pick the level that pays you and model that one. If billing happens at the workspace, the workspace is your account. Flattening one level of an org chart into an attribute like parentOrgName is almost always better than trying to represent the whole tree.

Naming attributes so they survive

Name attributes after the question they answer, not after your internal column name.

Weak nameBetter nameWhy
stripe_plan_nicknameplanThe segment builder is read by marketers
sub_statussubscriptionStatusAbbreviations age badly
numseatsSay what is being counted
date1trialEndsAtDates need a verb and a tense
is_paying_customer_flagisPayingDrop redundant suffixes

Three rules keep the set clean. Pick one casing convention and apply it everywhere, because trialEndsAt and trial_ends_at will eventually both exist and half your segments will match nothing. Keep types stable, so a value that is a number stays a number and never becomes the string "12". And use ISO dates, since 2026-09-20 sorts and compares correctly while Sept 20 does not.

Choosing roles

Resist the urge to mirror your permission system. Email routing is coarse. Three roles cover nearly everything:

  • owner - can pay. Gets billing, trial, renewal, and dunning email.
  • admin - can configure and invite. Gets seat limits, permission changes, security notices.
  • member - uses the product. Gets product education and launches.

Map your product's roles onto these by asking who can pay, who can configure, and who just uses it. A product with billing_admin, workspace_admin, editor, and viewer collapses cleanly: the first becomes owner, the second admin, and the last two members.

One nuance worth planning for: a contact can belong to more than one account. Consultants, agencies, and anyone with a personal workspace next to a work one will hit this. Make sure your role logic reads the role for the specific account in context rather than assuming one role per person.

Bootstrap from the events you already send

The last piece of advice is the one that saves the most time. Before writing any sync code, look at your existing event stream. If your events carry workspaceId, organizationId, or teamId properties, you have been describing accounts all along without naming them.

Sequenzy scans for exactly those org-like properties and offers a one-click backfill that creates accounts and memberships from your history. That gives you a populated model to explore before you commit to a schema, which is the right order: look at real data, see which attributes you actually reach for when building a segment, then write the sync for those and only those.

Start narrow. Identity, membership, four attributes, four events. You can always add the fifth attribute the week you need it.