Tenancy
Open in
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.
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
| Family | What it does |
|---|---|
| Scopes | The platform, then you, then each product, then each Customer org, then its principals. Every record, Event, Key and receipt belongs to exactly one |
| Namespaces | Each Customer org's records, files, Events and backups in a Namespace of its own: the unit of residency, backup, export and erasure |
| Isolation | A 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 file | A template per pattern, then your file, then each Customer's extension. Each layer changes only what the layer above leaves open |
| Installed extensions | Extensions other builders publish, installed into one Customer's layer and checked like its own |
| Provisioning | A Customer org and its Namespace made at first sign-up, in its region, on the Version it first calls |
| Offered again | Identity, the runtime, work and commerce, offered inside each Customer org for its own members, customers and suppliers |
| Payments for your Customers | Each Customer charges its own customers on its own connected Stripe account, and your fee comes off each charge |
| Sharing across orgs | A 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.
| Scope | What belongs to it | Who acts in it |
|---|---|---|
| The platform | Templates, the Verifier, the shared infrastructure | APIs.Dev |
| You | Your products, your team, your Stripe account, your Domains | You, your team and your agents, through the Build and Operator planes |
| A product | Its file, its Versions, its Offer, its site, portal and docs | You; anyone its Offer serves reads it |
| A Customer org | Its Namespace, members, Keys, mandates, extension and connected account | Its members and agents, under its admin's Roles |
| A Customer's own customer | An account inside that Customer's Namespace | Itself, under that Customer's Roles |
| A principal | Its sessions and Keys, and a mandate when it is an agent | Itself, 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
| Thing | States | What moves it |
|---|---|---|
| A Customer account | invited, active, past_due, suspended, closed, erased | Sign-up, Stripe, and the Customer operations in Trust and operations |
| A Namespace | provisioning, serving, moving, frozen, erased | First sign-up provisions it; a suspension freezes it with every record kept; an erase follows an export |
| A move | planned, copying, then done or halted | A 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 extension | checked, live, held | The Customer's admin deploys it; your deploy holds it when it no longer checks |
| An installed extension | installed, live, held, removed | The Customer's admin; its publisher's new Version is checked before it reaches the layer |
| A connected account | onboarding, enabled, restricted | Stripe's onboarding of the Customer, and any later request Stripe makes |
| A cross-org grant | offered, accepted, revoked | One 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 declare | The platform does |
|---|---|
| Nothing for tenancy | Makes a Customer org and its Namespace at first sign-up, and scopes every read, write, search, Watch and export to it |
| The regions you serve | Provisions each Namespace in the region its admin picks, and moves it with its records, files and backups |
extend: what each Customer may add | Checks each extension on every deploy, yours and theirs, and holds one that no longer fits |
| Isolation, by plan | Places each Namespace on shared infrastructure or its own, and moves it when the plan changes |
payments in offer: your fee on your Customers' own sales | Onboards 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 from | Gives 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.
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.
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:, 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
| Subsystem | What tenancy takes from it | What it gives back |
|---|---|---|
| Definition and compile | Your file and extend | A layer per Customer, checked on every deploy; a held extension keeps its Customer on the Version before |
| Identity, access and policy | Orgs, members, Roles, mandates, grants | The scope every principal acts in; a mandate never reaches past its org |
| Model and records | Records, files, history, projections | A Namespace per Customer: residency, backup, export and erasure as one |
| Data and Sources | Each Customer's Integrations and their credentials | Credentials held per Namespace; one Customer's systems never answer another |
| Runtime | The gate, Workflows, Watches, the change feed | Every run, Watch and feed inside one Namespace; a Customer's own Workflows run in its layer |
| Work | Cases, queues, suppliers | A queue per Customer, and a grant for a case two orgs share |
| Commerce | Connected accounts, your fee, the sales record | Each Customer's own sales on its own account, and your fee line by line |
| Interfaces and distribution | Every Interface, the portal, the UI contracts | A Customer's own fields and Verbs on its own Interfaces only; its branding tokens for its own customers |
| Trust and operations | Residency, backups, Customer operations | Provision, 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.
Identity, access and policy
Who acts, for whom and under what authority, and the one decision every move passes: allowed, pending, or refused with a cure.
Model and records
Each Customer's Things, with their Relationships, state, history, files and content, and the search, views and metrics rebuilt from them.