The Build and Operator planes
Open in
A plane is the set of Verbs one kind of principal acts through. You build through the Build plane, and run Customers and money through the Operator plane, over the API, the CLI or MCP.
Calls cross the seam inward and Events cross it outward. Filled: inside the product. A console renders these Verbs and keeps no state of its own.
Four planes share the one decision. Each console renders one or more of them and invents nothing. If a console needs a state, a move or a reason that no plane holds, the platform is missing a capability.
| Plane | Who acts through it | Specified in |
|---|---|---|
| Build | You, your team and your coding agent | Build, below |
| Operator | You, your staff and your operator agents | Operator, below |
| Customer | Each Customer's members and agents | The developer portal |
| Supply | Suppliers, workers and their agents | Supply, booking and fulfilment |
Capability families
The Build plane
| Family | Verbs | What they do |
|---|---|---|
| Products | Product.create, Product.list, Product.archive | Start a product from a template, list yours, and archive one with its record kept |
| Check and plan | Check.run, Plan.create | Every Problem and every breaking change, with price and margin per Verb, before anything serves |
| Deploy and roll back | Deploy.create, Rollback.create | Publish a Version to every Interface at once, or move them all back |
| Versions | Version.list, Version.deprecate, Version.retire | What each Key, run and case is pinned to; a deprecation with its window; retirement once nothing is pinned |
| Environments | Environment.promote | The move from Test to Live, which a person approves |
| Secrets | Secret.set, Secret.rotate, Secret.delete | A Source's credentials, outside the file and never shown |
| Domains | Domain.add, Domain.verify, Domain.remove | Your Domains for the API, the site, the portal and the docs, beside the free Host |
| Extensions | Extension.list, Extension.get | Each Customer's extension, and the line that holds one |
| Your team | Teammate.invite, Teammate.remove, Teammate.assign, Token.create, Token.revoke | Who on your team builds or operates, under which Role, and tokens for CI and agents |
The Operator plane
| Family | Verbs | What they do |
|---|---|---|
| Customers | Customer.list, Customer.search, Customer.get | Each Customer's plan, usage, spend, region, extension, members and open disputes |
| Plans and credits | Subscription.change, Subscription.cancel, Credit.grant, Coupon.create | A plan change, a cancellation, credits or a coupon, each at the Offer's prices |
| Refunds and disputes | Refund.grant, Refund.decline, Dispute.answer | Refunds outside the published rule, decided by the person you name; disputes answered with the receipt and the call record |
| Payouts and the sales record | Payout.list, Payout.get, Sale.list, Sale.export | Every payout to you and to each supplier, and every sale, refund, fee and tax line behind it |
| Support access | SupportGrant.request, SupportGrant.end, SupportGrant.reads | Time-boxed access a Customer consents to, and every read made inside it |
| Incidents | Incident.open, Incident.update, Incident.resolve | Posts to the status page on your Domain and to every Watch |
| Calls and evidence | Call.get, Call.replay, Log.follow, Trace.get | Any call by its request id, replayed against its Version; logs as they happen; a trace across every hop |
| Brakes and approvals | Brake.release, Approval.grant, Approval.decline | A held run released, or a move held for a person decided |
| Customer operations | Customer.provision, Customer.suspend, Customer.restore, Customer.move, Customer.offboard, Customer.erase | Each with its reason and its Event, and the Customer told |
| Suppliers | Supplier.verify, Supplier.pause, Supplier.remove | Who may sell in a Marketplace or a Service API, and a stop with the record kept |
| Keys | Key.revoke | A leaked Key revoked, and its holder told |
The Operator plane sees each Customer's account, plan, usage and money. It never reads inside a Customer's Namespace without a support grant.
A refund the published rule allows needs no plane: it is paid with no person. The planes hold what needs you. A support desk, a sales funnel and the company's books run outside the product, on its Events and through these Verbs.
Lifecycles and states
| Thing | States | What moves it |
|---|---|---|
| A deploy | pending, then done or refused | Deploy.create; a refused deploy changes nothing that serves |
| A Version | live, superseded, deprecated, retired | The next deploy, a deprecation with its window, and retirement when nothing is pinned |
| An environment | test, then live | Environment.promote, approved by a person |
| A Domain | added, verifying, verified, removed | One DNS record verifies it; the free Host keeps answering throughout |
| A teammate | invited, active, removed | You or an admin on your team; a removal ends every token they made |
| A Customer account | invited, active, past_due, suspended, closed, erased | Sign-up, Stripe, and the Customer operations; a restore returns suspended to active |
| A support grant | requested, then consented or declined; a consented grant is active, then ended | The Customer's admin consents; the time box, the Customer or you end it |
A Refund | requested, granted or declined, paid | The published rule with no person, or the approver you name |
A Dispute | opened, answered, then upheld or denied | The Customer opens it with the receipt; you answer with the call record and terms |
A Payout | earned, pending, paid, or reversed | Stripe's schedule; a refund or an upheld dispute reverses its line |
| An incident | investigating, identified, monitoring, resolved | A failing check opens it; each update posts to the status page and to Watches |
| A brake | armed, tripped, held, then released or reset | A cap reached before a call runs; a person releases it, or the period resets it |
| A supplier | applied, verifying, verified, paused, removed | Verification, then you or the supplier |
Each row is the same state the Customer, the supplier or the buyer sees on its own side. Each move writes its Event and its actor: a person under a Role, or an agent under a mandate.
What you declare, what the platform does
| You declare | The platform does |
|---|---|
| Your team's Roles: who builds, who operates, and which Verbs each may call | Applies them to every plane Verb on every Interface; a missing Role answers 403 role_required |
| Approvals on operator moves: a refund above an amount, an erase, the move to Live | Holds the move, sends the Approval URL, and runs it once on the grant |
| What your agents may do alone | Requires a mandate on every agent call, and holds the moves you reserve for a person |
| How long support access lasts, and what it may read | Asks the Customer's admin to consent, opens the grant for that long, and records every read |
| Nothing else | Every plane Verb on the API, the CLI and MCP; an Event for every act; the evidence of every decision |
Example
Pipeline's team splits support from finance, holds refunds above $100 for finance, and caps support access at two hours of reads.
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'] },
},
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,
},
operate: {
team: { // your staff, not your Customers' members
support: ['Customer.get', 'SupportGrant.request', 'Incident.update'],
finance: ['Refund.grant', 'Credit.grant', 'Payout.list'],
},
approve: { 'Refund.grant': { above: 100, by: 'finance' }, 'Customer.erase': { by: 'owner' } },
agents: { approve: ['Customer.suspend'] }, // an operator agent's suspension waits for a person
support: { for: '2h', see: ['Company', 'Deal'] }, // read-only, and only with consent
},
})The operator agent asks Acme for access to look into a refused move. Nothing is read until Acme's admin consents.
HTTP/1.1 202 Accepted
Content-Type: application/ json
Location: /v1/ products/ pipeline/ customers/ cus_Acme/ support-grants/ grant_1
X-Action-Id: act_31
X-Cost: price= 0, currency= "USD"
X-Request-Id: req_2a7d90c4e1b35f68a0c2
{
"id": "grant_1",
"customer": "cus_Acme",
"see": ["Company", "Deal"],
"for": "2h",
"status": "requested",
"reason": "Deal.win refused with wrong_state since 09: 00",
"consent": "https: //pipeline.apis.dev/ consents/ grant_1",
"mandate": ["you", "agent_ops"]
}That is POST https:, npx apis.dev support request cus_Acme --for 2h in the CLI, and requestSupportGrant over MCP. Acme's admin consents on the link or through the API, and each read lands in Acme's audit log as it happens.
Contracts with the other subsystems
| Subsystem | What the planes take from it | What the planes give back |
|---|---|---|
| Definition and compile | Check, plan, deploy, rollback, the Digest | Every deploy as a Verb with its actor, a person or an agent under a mandate |
| Identity, access and policy | Your team's Roles, operator mandates, approvals, consent | Every plane act through the one decision; support access as a grant the Customer holds |
| Model and records | Each Customer's account, Namespace and views | Reads across your Customers' accounts, never inside a Namespace without a grant |
| Data and Sources | Each Source's health and licence terms | A Source's failure opened as an incident, with its trace |
| Runtime | The gate, Actions, Events | Every plane act through the same gate; held runs to release |
| Work | Queues, cases, suppliers | Supplier verification and pauses; a stuck task reassigned |
| Commerce | Subscriptions, refunds, disputes, payouts, the sales record | Refunds outside the rule, credits and plan changes, each at the Offer's prices |
| Interfaces and distribution | The status page, the changelog, the portal | Incident posts and deprecation notices on your Domain; the same states the portal shows |
| Trust and operations | Incidents, brakes, the proof record, Customer operations | The Verbs that move each, and the evidence of who moved it |
What your team and your Customers meet
- Your coding agent. It writes the file, checks, plans, deploys and rolls back through the Build plane, under a token or mandate you give it.
- Your operator agent. It sees a Customer turn
past_due, reads the account and proposes a suspension, which waits for a person. A refund above $100 waits for finance. - Your staff. Each sees only the Verbs their Role holds, in any console or the CLI, and every act carries their name.
- Customers. Your support team reads nothing without its consent. A suspension names its reason and its cure, and every change you make shows in its portal as an Event.
- A supplier. A pause or a removal names its reason, and its payouts and track record are kept.
- Any console. It renders the planes and invents nothing: no state, no move and no reason of its own.
Every act a console offers is a Verb first, so the product runs the same whether a person clicks or an agent calls.