---
title: "Identity, access and policy"
url: /identity
---

# 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.

Identity, access and policy says who acts, for whom and under what authority. One decision answers every move before it runs: allowed, pending, or refused with a cure.

## Capability families
| Family | What it does |
| --- | --- |
| Principals | People, agents, [Keys](/reference/platform.md#key) and apps, each acting for exactly one Customer org, or for you |
| Progressive identity | An agent pays for one call with no account, a Key adds a Customer, and an org adds members, Roles and single sign-on |
| Tenancy | You, then each product, then each Customer org, then its principals; each org's records live in its own [Namespace](/reference/platform.md#namespace) |
| Orgs and members | Orgs, members, invites, join by a checked email domain, teams, seats, single sign-on and directory sync, apps a Customer connects |
| Roles and permissions | The [Roles](/reference/platform.md#role) you declare and the custom Roles a Customer's admin composes from them; permissions per Verb, per field and per record |
| Mandates | The chain from a person to an org to an agent to a sub-agent; each link scoped, budgeted, time-boxed and revocable, and narrower than the one above |
| Approvals | A person approves a class of move: above an amount, by an agent, or out of hours; the move waits, then runs once |
| Authority beyond Roles | Credentials a person holds, acts reserved to a licensed or legally human party, and the jurisdictions an act is valid in |
| Parties without accounts | A signer, a witness or a counterparty acts once through a single-use link; a grant lets several orgs share one case |
| Support access | Access a Customer consents to, time-boxed and recorded read by read, offered as Verbs for your operator console |

### One decision, three answers
Every move asks one question. May this principal, under this mandate, make this Verb on this record, in this state, now, at this price, under these terms and consents?

| Input | Where it comes from |
| --- | --- |
| The principal, its Roles and its credentials | This subsystem |
| The mandate chain | This subsystem, and the buy side of Commerce |
| The record and its state | Model and records |
| The [Entitlement](/reference/platform.md#entitlement), the price, the budget | Commerce |
| Licence terms | Data and Sources |
| Consent, residency and the legal floor | Trust and operations |

The answer's status follows what lifts it, on every [Interface](/every-product.md).

| Answer | What the caller gets | What lifts it |
| --- | --- | --- |
| Allowed | The move runs: 200 or 201 with the record, or 202 with its [Action](/workflow.md#the-lifecycle) | Nothing |
| Pending | 403 [`approval_required`](/reference.md#approval_required) with an Approval URL; inside a run, the Action waits | A person who approves, signs or supervises |
| Refused, cured by payment | 402 with `offers`, each with its Stripe Checkout link: the OFFER shape, a price to go on at | A payment, then the same call |
| Refused, by the clock | 429 with `Retry-After` | Time |
| Refused, by authority or state | 403 [`role_required`](/reference.md#role_required) or [`not_entitled`](/reference.md#not_entitled), 409 [`wrong_state`](/reference.md#wrong_state) with `allowed` | Another member, another plan, or another move first |

The same decision governs a Customer's own agent spending its budget with other sellers.

## Lifecycles and states
| Thing | States | What moves it |
| --- | --- | --- |
| A member | `invited`, `active`, `suspended`, `removed` | An admin's invite, the member's accept, an admin or directory sync; a removal is restorable |
| A Key | `active`, `rolled`, `revoked` | A roll keeps the old secret answering for its grace period; a revoke ends it at once |
| A mandate | `active`, `suspended`, then `exhausted`, `expired` or `revoked` | Spend, time or its issuer; revoking a link revokes every link below it |
| An approval | `requested`, then `granted`, `declined` or `expired` | The approver; a grant resumes the waiting move once |
| A support grant | `requested`, `consented`, `active`, `ended` | The Customer's admin consents; the time box ends it |
| A single-use link | `sent`, then `used` or `expired` | The party's one act |

Every move above is a Verb and writes its Event, so `Mandate.revoked` and `Approval.granted` reach a [Watch](/reference/platform.md#watch) like any other.

## What you declare, what the platform does
| You declare | The platform does |
| --- | --- |
| Roles, and what each sees | Applies each Role to every read, list, search, view, metric and export, on every Interface |
| A Role on a move or a step | Answers 403 `role_required` to anyone without it, and routes a human step to someone with it |
| Approvals by class of move | Holds the move, sends the Approval URL, and runs it once on the grant |
| What agents may do alone | Requires a mandate on every agent call, checks each link, and holds the moves you reserve for a person |
| Credentials and reserved acts | Sends a reserved act to its person through a single-use link, and records who made it |
| Nothing else | Orgs, invites, seats, single sign-on, directory sync, Keys, OAuth for apps, support access, and the record of every decision |

### Example
Reps see their own Deals, a manager sees all of them, and a win an agent proposes waits for a person.

```ts title="definition.ts"
import { define } from 'apis.dev'

/** Deals for each Customer, kicked off when won. */
export default define({
  name: 'pipeline', domain: 'pipeline.apis.dev',
  …
  roles: {
    rep:     { see: { Deal: 'own' } },             // a rep sees the Deals they opened
    manager: { has: 'rep', see: { Deal: 'all' } },
  },
  Deal: {
    title: 'string', amount: 'decimal(12,2)', company: '->Company.deals',
    stage: {
      open: [], qualify: 'opened', lose: ['opened', 'qualified'],
      win: { in: 'qualified', role: 'manager', approve: { above: { amount: 50000 } } },
    },
  },
  agents: { approve: ['Deal.win'] },               // an agent's win waits for its person
  offer: { Team: { month: 49, seats: 5, seat: 9 }, 'Deal.open': 0.001 },
})
```

```http title="Response"
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
X-Cost: price=0, currency="USD"
X-Request-Id: req_7c1e09b3a4d2f6e85b10

{
  "type": "https://pipeline.apis.dev/docs/errors#approval_required",
  "title": "Forbidden",
  "status": 403,
  "detail": "An agent's Deal.win waits for its person to approve.",
  "code": "approval_required",
  "approval": "https://pipeline.apis.dev/approvals/apr_1",
  "mandate": ["dana@acme.com", "org_acme", "agent_7"],
  "instance": "req_7c1e09b3a4d2f6e85b10"
}
```

## Contracts with the other subsystems
| Subsystem | What it gives this one | What this one gives back |
| --- | --- | --- |
| Definition and compile | Roles, the Role on each move, approvals, the agent policy, the extension policy | Who may deploy, and who may extend each Customer's layer |
| Model and records | The record, its state and its [Relationships](/patterns/headless-saas.md) | A mask on every field and record a principal may not see, applied before any projection answers |
| Data and Sources | Licence terms; each Customer's [Integrations](/patterns/headless-saas.md#integrations) | The Customer's consent to connect, held as a grant and revocable |
| Runtime | One request per move, at the gate's `decide` step | One answer, which the gate renders and records |
| Work | Credentials, licensed Roles, cases that span orgs | Who may claim, review, supervise or sign; single-use links for parties without accounts |
| Commerce | Entitlements, the price, budgets, buy-side mandates | The mandate chain, which Commerce narrows at every hop and a seller verifies |
| Interfaces and distribution | Every call and message, from every Interface | The answer for each Interface; the allowed and refused moves in the affordance contract |
| Trust and operations | Residency, consent, brakes | Every decision as evidence: what was enforced, on which input, and why |

## What Customers and their agents meet
- **An admin's setup.** Create the org, invite members, set Roles and connect single sign-on, through the API, the portal or MCP.
- **A member's view.** Each member sees only what their Role allows, in every list, search and metric. An empty result carries its reason.
- **An agent's mandate.** An agent presents its mandate on every call, a signed statement the seller verifies, carried over MCP with its OAuth token. Past its scope or budget it is refused with a cure, and a person's approval resumes it.
- **A party without an account.** A signer or a counterparty gets a single-use link, makes one act, and the record shows who made it.
- **Support, by consent.** A Customer's admin grants support access for a time box and reads each access as it happens.

---

Every move, from a person, an agent or an app, meets the same one decision and gets the same three answers.