Concepts · Clients

Clients

A workspace is Esy’s customer: an agency, a freelancer, a company. A client is their customer: the dental group, the bakery, the law firm they do the work for. A client groups the projects that are its domains and carries the business — whether it is active, what it pays, and who approves the work.

Who is who

WORKSPACE · ESY’S CUSTOMERBright AgencyNorthside Dentalclient · active · retainerJuniper Bakeryclient · leadYour brandsprojects with no clientnorthsidedental.comnorthside.kidsclip.artseo.page
A workspace, its clients, and its own brandsProjects stay the scope that runs, budgets and costs hang off. A client sits above the projects that are its domains; a project with no client is one of your own brands.
ThingWhat it isExample
WorkspaceEsy’s customer. Members, budgets and billing with Esy live here.Bright Agency
ClientA business the workspace works for, with a status, terms and contacts.Northside Dental
ProjectA domain-level scope that runs, budgets and costs belong to. It may belong to a client.northsidedental.com
ContactA person at a client. Not an Esy login unless invited.Dr. Patel, who approves the work

There is no “agency” or “freelancer” kind of workspace, and no kind of client: a freelancer is a one-person agency, and the difference between a lead and a client is its status.

Billing terms

Terms are a small versioned document on the client. Esy validates every write; the database checks the envelope. Money is integer cents with a currency, never a float.

billingjson
{
  "version": 1,
  "model": "retainer",          // retainer | per_job | hourly | none
  "amountCents": 300000,        // integer cents, never floats
  "currency": "usd",
  "period": "quarter",          // retainers only: month | quarter | year
  "scope": [{ "what": "City pages", "count": 12, "per": "month" }],
  "startsOn": "2026-10-01",
  "renewsOn": "2027-04-01"
}

A retainer needs a period; only a retainer has one; anything paid needs an amount. Esy records the terms and computes the expected monthly fee from them. It does not send invoices; payments, if you attribute them, live in your own Stripe, referenced by stripeCustomerId.

Status

lifecycleascii
lead → active ⇄ paused → past
every change is a row in the client's status history, with who and why

Leads and past clients stay out of totals. The history is append-only: a client with history can be archived, never deleted.

What rolls up to a client

FigureFromWho sees it
Cost to serveProvider costs of runs in the client’s projects, this monthOwners and admins
Expected feeThe billing terms, per monthOwners and admins
Waiting on youRuns in review in the client’s projects, last 14 daysMembers
MadeArtifacts made in the client’s projects this monthMembers
Safe by construction

A project can only belong to a client in its own workspace, and a contact can only belong to a client in its own workspace. The database enforces both with composite keys, so no bug in a client app can link across organizations. Edits carry the etag and creates take a requestId, as everywhere in the API.

The endpoints are in the Clients API. Characters (avatars) belong to a project, so a client’s avatars are its projects’ avatars: see Characters.

In short
  • A workspace is Esy’s customer; a client is the workspace’s customer.
  • A client groups projects and carries the business: status, terms, contacts.
  • A project with no client is one of your own brands.
  • Tenancy is enforced by the database, not by careful code.