# Identity and access

URL: /code/platform/identity-and-access · Id: `page:code/platform/identity-and-access`

> How api.sb knows who is calling and what the call may do, before it runs.

Every call to [api.sb](/code/platform/api-sb) answers three questions before it runs: who is acting, for whom, and by what right. The answers stay on the [Action](/business/nouns/action) forever.

## Who is acting
Three kinds of caller reach a [Startup](/business/nouns/startup). [People](/business/nouns/person) sign in once, with a passkey, an email link, or their own single sign-on. [Agents](/business/nouns/agent) carry their own credentials and never borrow a person's; programs hold a key.

A key starts with `sk_test_` or `sk_live_`, and the prefix picks the environment. A key acts only in its own namespace and within its scopes. A key can mint a narrower key for a script or an Agent; no key can mint a wider one.

```bash
curl https://api.sb/acme.com/orders \
  -H "Authorization: Bearer sk_test_..."
```

A missing or expired key returns [unauthorized](/code/api/errors/unauthorized). A valid key without the right returns [forbidden](/code/api/errors/forbidden), and the error names the grant the caller lacks.

## For whom
An Agent often acts for someone else: a founder, a [Customer](/business/nouns/customer), or the Startup itself. It does so under a [Mandate](/business/nouns/mandate), a standing authorization to perform one [Verb](/business/nouns/verb) within a [Limit](/business/nouns/limit) until the Mandate expires. [Authorize](/business/nouns/mandate/authorize) grants one; [revoke](/business/nouns/mandate/revoke) ends it at once.

**Ask**

```text
Let the support agent refund invoices up to $100 without asking me.
```

**API**

```bash
curl -X POST https://api.sb/acme.com/mandates/authorize \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent":"agent_1","verb":"Invoice.refund","limit":"limit_100_usd"}'
```

**SDK**

```ts
import { $ } from 'startup-builder'

await $.Mandate.authorize({ agent: 'agent_1', verb: 'Invoice.refund', limit: 'limit_100_usd' })
```

**CLI**

```bash
npx startup-builder do Mandate.authorize --json '{"agent":"agent_1","verb":"Invoice.refund","limit":"limit_100_usd"}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "code": "return await $.Mandate.authorize({ agent: 'agent_1', verb: 'Invoice.refund', limit: 'limit_100_usd' })"
  }
}
```

Every Action records two names: the [Worker](/business/nouns/worker) that acted and the [Party](/business/nouns/party) it acted for. An auditor reading a refund sees which Agent issued it and on whose authority.

## By what right
A right always names a Verb on a [Noun](/business/nouns/noun), within a scope, and may carry a Limit. Three grants supply it, and their origin matters.

| Grant | Comes from | Example at a churn-report Startup |
| --- | --- | --- |
| [Permission](/business/nouns/permission) | A [Role](/business/nouns/role) | The analyst Role may create and deliver reports. |
| [Entitlement](/business/nouns/entitlement) | An accepted [Offer](/business/nouns/offer) | A Customer on the weekly plan may read reports in its own [Tenant](/business/nouns/tenant). |
| [Mandate](/business/nouns/mandate) | A Party's authorization | The support Agent may refund up to $100 per [Invoice](/business/nouns/invoice). |

A person changing Roles gains and loses Permissions at once. A Customer that cancels loses its Entitlements at the end of the paid [Period](/business/nouns/period). Nothing is granted by a screen: hiding a button is design, not access control.

## Limits become Approvals
A Limit bounds an amount, a count, or a rate over time, and api.sb checks it before every call. An Agent, a person, and a scheduled [Workflow](/business/nouns/workflow) meet the same check.

A call over its Limit does not fail. It waits as an [Approval](/business/nouns/approval), a [Task](/business/nouns/task) for a Worker with the authority to allow or refuse it. The support Agent's $250 refund waits for a person; its $40 refund runs at once.

## Customers and their teams
People from a Customer sign into the Startup's [App](/business/nouns/app) and see only their own Tenant. A Customer that is an [Organization](/business/nouns/organization) connects its own single sign-on and directory. Its people then join and leave the Tenant as they join and leave the Organization.

Because api.sb checks every call, every [Interface](/business/nouns/interface) enforces the same rules. A Customer reading reports over MCP sees exactly what the [Portal](/business/nouns/portal) shows them.

| Term | Kind | Definition |
| --- | --- | --- |
| [Security](/workflows/processes/security) | Process | Security keeps every Permission earned, every secret fresh, and every access recorded. |
| [Access Level](/business/nouns/access-level) | Noun | An Access Level is a named preset of Permissions a Worker holds in a namespace, such as owner or viewer; it is never a Role. |
| [API Key](/business/nouns/api-key) | Noun | An API Key is a secret a Startup issues to one Customer, which signs that Customer’s calls to its API, SDK, CLI and MCP server. |
| [Approval](/business/nouns/approval) | Noun | An Approval is a Task to allow or refuse one pending Action that exceeds a Limit or a Mandate. |
| [Entitlement](/business/nouns/entitlement) | Noun | An Entitlement is what a Customer gets from an accepted Offer: a Verb on a Noun in its Tenant, optionally bounded by a Limit. |
| [Human](/business/nouns/human) | Noun | A Human is a Worker who is a person, acting on Tasks through Apps, Mailboxes, and Channels. |
| [Limit](/business/nouns/limit) | Noun | A Limit is a bound on a Permission, Entitlement, or Mandate, checked before every call; exceeding it creates an Approval. |
| [Mandate](/business/nouns/mandate) | Noun | A Mandate is a standing authorization for an Agent to act for a Party, within Permissions and Limits, until it expires. |
| [Permission](/business/nouns/permission) | Noun | A Permission is what a Role may do: a Verb on a Noun within a scope, optionally bounded by a Limit. |
| [Person](/business/nouns/person) | Noun | A Person is a human with one identity across every Startup; each Startup’s Contact is its own view of that Person. |
| [Tenant](/business/nouns/tenant) | Noun | A Tenant is the partition of a Startup’s data that belongs to one Customer. |
| [APIKey.issue](/business/nouns/api-key/issue) | Verb | Issue creates an API Key for one Customer and returns its secret once; afterwards only the prefix shows. |
| [APIKey.revoke](/business/nouns/api-key/revoke) | Verb | Revoke stops an API Key at once: its next call fails with 401, and the record and its history stay. |
| [APIKey.roll](/business/nouns/api-key/roll) | Verb | Roll issues a replacement API Key with the same scope and keeps the old one working until a set time. |
| [Approval.approve](/business/nouns/approval/approve) | Verb | Approve allows the pending Action an Approval holds, and that Action runs. |
| [Approval.refuse](/business/nouns/approval/refuse) | Verb | Refuse declines an Approval, which sets the Action it holds to `refused` with the reason given. |
| [Entitlement.check](/business/nouns/entitlement/check) | Verb | Check says whether a Customer may call a Verb now, how much of its Limit remains, when that resets, and which Offer lifts it. |
| [Human.invite](/business/nouns/human/invite) | Verb | Invite asks a person to join a Startup in a named Role, sharing that Role’s work with its Agent. |
| [Human.onboard](/business/nouns/human/onboard) | Verb | Onboard admits a recruited Human to supply work once their identity, Credentials and payout details verify. |
| [Limit.raise](/business/nouns/limit/raise) | Verb | Raise lifts a Limit after an Approval allows it, and the Action that waited on it proceeds. |
| [Mandate.authorize](/business/nouns/mandate/authorize) | Verb | Authorize grants an Agent a standing Mandate to perform a Verb within a Limit, without asking each time. |
| [Mandate.pause](/business/nouns/mandate/pause) | Verb | Pause stops every new Action under a Mandate at once and keeps its scope, so it can resume unchanged. |
| [Mandate.resume](/business/nouns/mandate/resume) | Verb | Resume restarts a paused Mandate with its scope, Limits and approval rule unchanged. |
| [Mandate.revoke](/business/nouns/mandate/revoke) | Verb | Revoke ends a Mandate at once, so new Actions under it are refused and running ones finish. |
| [Offer.grant](/business/nouns/offer/grant) | Verb | Grant adds an Entitlement to an Offer: a Verb its Customers may call, optionally bounded by a Limit. |
| [Startup.claim](/business/nouns/startup/claim) | Verb | Claim binds a provisional Startup to a verified owner, which enables payments and every Verb that moves money. |
| [Tenant.invite](/business/nouns/tenant/invite) | Verb | Invite asks a Person to join a Customer’s Tenant, and resizes the Subscription when the Offer prices per member. |
| [Tenant.provision](/business/nouns/tenant/provision) | Verb | Provision creates a Customer’s Tenant in a Startup’s App, holding that Customer’s records apart from every other. |

## Next
- [Workflows](/code/platform/workflows): how an Action waits for an Approval and resumes.
- [Permission](/business/nouns/permission): the full reference.
- [Errors](/code/api/errors): every error a refused call returns.