Skip to content

Tenancy

Tenancy says where every record lives and whose rules it follows. Each Customer gets its own Namespace and its own layer of your file, and the platform is offered again inside it for its own customers.

Tenancy goes down

Each box holds the next, and every record belongs to one. Filled: a Namespace, which nothing reads across. Each layer of the file narrows the one above it.

Capability families

FamilyWhat it does
ScopesThe platform, then you, then each product, then each Customer org, then its principals. Every record, Event, Key and receipt belongs to exactly one
NamespacesEach Customer org's records, files, Events and backups in a Namespace of its own: the unit of residency, backup, export and erasure
IsolationA Namespace on shared infrastructure, or on infrastructure of its own for a Customer who needs it; the Interfaces and the file are the same on both
Layers of the fileA template per pattern, then your file, then each Customer's extension. Each layer changes only what the layer above leaves open
Installed extensionsExtensions other builders publish, installed into one Customer's layer and checked like its own
ProvisioningA Customer org and its Namespace made at first sign-up, in its region, on the Version it first calls
Offered againIdentity, the runtime, work and commerce, offered inside each Customer org for its own members, customers and suppliers
Payments for your CustomersEach Customer charges its own customers on its own connected Stripe account, and your fee comes off each charge
Sharing across orgsA grant that lets two orgs work one case. Records are never copied, and either org revokes the grant

Nothing reads across Namespaces. A search, a metric, an export and an agent's tools stop at the Namespace's edge; the one way across is a grant both orgs accept.

ScopeWhat belongs to itWho acts in it
The platformTemplates, the Verifier, the shared infrastructureAPIs.Dev
YouYour products, your team, your Stripe account, your DomainsYou, your team and your agents, through the Build and Operator planes
A productIts file, its Versions, its Offer, its site, portal and docsYou; anyone its Offer serves reads it
A Customer orgIts Namespace, members, Keys, mandates, extension and connected accountIts members and agents, under its admin's Roles
A Customer's own customerAn account inside that Customer's NamespaceItself, under that Customer's Roles
A principalIts sessions and Keys, and a mandate when it is an agentItself, inside its Roles and its mandate

Tenancy goes down and composition goes sideways. A product built on yours is another seller with scopes of its own, under composition.

Lifecycles and states

ThingStatesWhat moves it
A Customer accountinvited, active, past_due, suspended, closed, erasedSign-up, Stripe, and the Customer operations in Trust and operations
A Namespaceprovisioning, serving, moving, frozen, erasedFirst sign-up provisions it; a suspension freezes it with every record kept; an erase follows an export
A moveplanned, copying, then done or haltedA new region or isolation tier; the Namespace serves throughout and cuts over at once, and a halted move leaves it where it was
A Customer's extensionchecked, live, heldThe Customer's admin deploys it; your deploy holds it when it no longer checks
An installed extensioninstalled, live, held, removedThe Customer's admin; its publisher's new Version is checked before it reaches the layer
A connected accountonboarding, enabled, restrictedStripe's onboarding of the Customer, and any later request Stripe makes
A cross-org grantoffered, accepted, revokedOne org offers, the other accepts, and either revokes; a revoke ends every read at once

A frozen Namespace refuses calls with a reason and still answers its own export. Each move writes its Event: Namespace.provisioned, Namespace.moved, Extension.held, Grant.revoked.

What you declare, what the platform does

You declareThe platform does
Nothing for tenancyMakes a Customer org and its Namespace at first sign-up, and scopes every read, write, search, Watch and export to it
The regions you serveProvisions each Namespace in the region its admin picks, and moves it with its records, files and backups
extend: what each Customer may addChecks each extension on every deploy, yours and theirs, and holds one that no longer fits
Isolation, by planPlaces each Namespace on shared infrastructure or its own, and moves it when the plan changes
payments in offer: your fee on your Customers' own salesOnboards each Customer's connected account on Stripe, takes your fee on each charge, and prints it in the sales record
Roles your Customers may compose fromGives each Customer's admin custom Roles for its own members and its own customers

Example

Pipeline lets each Customer add fields, rules and Workflows to Deal, and serves the US and the EU. It takes 1% of what each Customer charges its own clients.

definition.ts
19 lines
import { define } from 'apis.dev'

/** Deals for each Customer, kicked off when won. */
export default define({
  name: 'pipeline', domain: 'pipeline.apis.dev',
  Company: { name: 'string', domain: 'url!#', deals: '<-Deal.company' },
  Deal: {
    title: 'string', amount: 'decimal(12,2)', company: '->Company.deals',
    stage: { open: [], qualify: 'opened', win: 'qualified', lose: ['opened', 'qualified'] },
  },
  extend: { Deal: { fields: 10, rules: true, workflows: true } },  // each Customer's layer
  operate: { regions: ['us', 'eu'] },                              // each Customer picks one
  offer: {
    Free: { month: 0, seats: 1, includes: { 'Deal.open': 25 } },
    Team: { month: 49, seats: 5, seat: 9, includes: { 'Deal.open': 1000 } },
    'Deal.open': 0.001,
    payments: { fee: 0.01 },             // your share of each charge a Customer makes
  },
})

One read answers where a Customer lives, what it has added, and how it takes payments.

Response
HTTP/1.1 200 OK
Content-Type: application/json
X-Cost: price=0, currency="USD"
X-Request-Id: req_6e0b3f19a27c4d58e2a1

{
  "id": "cus_Acme",
  "product": "pipeline",
  "status": "active",
  "plan": "Team",
  "version": "v4",
  "namespace": { "region": "eu", "isolation": "shared", "status": "serving" },
  "extension": {
    "status": "live",
    "digest": "sha256:9f2c41d7",
    "adds": ["Deal.region", "Deal.win above 20000", "Deal.won: invoice"]
  },
  "payments": { "account": "acct_Acme", "status": "enabled", "fee": 0.01 },
  "members": 7,
  "agents": 2
}

That is GET https://apis.dev/v1/products/pipeline/customers/cus_Acme, npx apis.dev customers get cus_Acme in the CLI, and getCustomer over MCP. When Acme wins a Deal, its own Workflow invoices the Company on acct_Acme, under Acme's name, and 1% of the charge is yours.

Contracts with the other subsystems

SubsystemWhat tenancy takes from itWhat it gives back
Definition and compileYour file and extendA layer per Customer, checked on every deploy; a held extension keeps its Customer on the Version before
Identity, access and policyOrgs, members, Roles, mandates, grantsThe scope every principal acts in; a mandate never reaches past its org
Model and recordsRecords, files, history, projectionsA Namespace per Customer: residency, backup, export and erasure as one
Data and SourcesEach Customer's Integrations and their credentialsCredentials held per Namespace; one Customer's systems never answer another
RuntimeThe gate, Workflows, Watches, the change feedEvery run, Watch and feed inside one Namespace; a Customer's own Workflows run in its layer
WorkCases, queues, suppliersA queue per Customer, and a grant for a case two orgs share
CommerceConnected accounts, your fee, the sales recordEach Customer's own sales on its own account, and your fee line by line
Interfaces and distributionEvery Interface, the portal, the UI contractsA Customer's own fields and Verbs on its own Interfaces only; its branding tokens for its own customers
Trust and operationsResidency, backups, Customer operationsProvision, suspend, restore, move, offboard and erase, one Namespace at a time

What Customers and their agents meet

  • Their own space. Every list, search, metric and export shows only their records. An empty result says why.
  • Their region. The admin picks a region at sign-up. Records, files and backups stay there, and a move keeps every record.
  • Their own shape. The admin, or the admin's agent, adds fields, rules and Workflows inside your limits, over the API, the CLI or MCP. A held extension names the line that no longer fits.
  • Their own customers. A Customer charges its own clients on its own Stripe account, under its own name. Its clients see its name on every invoice and receipt.
  • Their agents, fenced. An agent's mandate starts at its org and narrows from there. It never reaches another Customer's Namespace.
  • Nothing locked in. Export takes the whole Namespace, extension included, and an erase follows it.

Every record has one home, and every layer of the file narrows the one above, so no Customer's space leaks into another's.