> ## Documentation Index
> Fetch the complete documentation index at: https://docs.niadra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spaces and keys

> Project, environment, source and key: who talks to Niadra and what each key may do.

Everything that talks to Niadra talks through a key, and every key belongs to a source inside a space. Those three names decide where data lives, who is reading and what each agent may do with the memory. Knowing them before you integrate settles most permission questions up front.

## Project, environment and space

A **project** is the memory of one company, or of a business line that has to stay separate. Every project has two **environments**: `sandbox`, for building and testing, and `production`, for real traffic.

A **space** is the pair of project and environment. It is Niadra's unit of isolation: the space is the first column of every database key, cache key and encryption context, so a sandbox event never shows up in a production read, and one company's data never decrypts under another company's key.

Each space lives in one region, its project’s, and has a stable address:

```text theme={null}
https://<space>.<region>.api.niadra.com
```

The SDK builds that address from the key. You configure no URL at all, except to point at the local emulator.

## Sources

A **source** is anything that talks to the memory: one vendor's voice agent, another vendor's WhatsApp agent, your internal billing agent, the CRM that sends events by webhook, the human attendant who gets context inside the tool your company already uses. Every source has:

| Attribute                | What it is for                                                                                                                                                                                           |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `purposes`               | What it reads and why, such as `customer_service` or `billing`. The policy grants each category of memory by purpose.                                                                                    |
| `audience`               | `customer_agent`, `internal_agent`, `human`, `reviewer`, `analyst`, `trigger_target` or `export`. It decides what the source may read, sets the default scopes of its keys and appears on every receipt. |
| `vendor` and `channel`   | Who built the agent and where it works. Measurement groups by them.                                                                                                                                      |
| `verification_ceiling`   | The highest level the source may declare, V2 by default. Automated agents: V2. Sources that run OTP: V3. V4 only for human desks and systems of record.                                                  |
| `confirms_before_acting` | Marks agents whose prompt makes them confirm values, so measurement does not count those confirmations as repetition.                                                                                    |
| `navigation_enabled`     | Whether the source may use the history tools. On by default.                                                                                                                                             |
| `trusted_action_ops`     | With `act`, the closed list of operations the source may record, such as `credit`. Empty means any operation.                                                                                            |
| `critical`               | Keeps the source out of experiment control groups: its customers always get the memory.                                                                                                                  |

You create and configure sources in the Console or through the [control API](/en/api/control/sources-create). Access to memory is denied by default and granted by purpose: broad access to the ERP does not give an internal agent broad access to the memory. Before you grant access, [`POST /v1/policy/simulate`](/en/api/policy-simulate) shows what a source, audience or purpose would see of a profile, item by item, with what would be withheld and why.

## Keys

Each source has one or more keys. The format carries everything the SDK needs to find the address:

```text theme={null}
nia_sk_<live|test>_<region>_<space>_<key_id>_<secret>
```

* `live` reaches production spaces; `test` reaches sandbox spaces.
* `region` and `space` become the address `https://<space>.<region>.api.niadra.com`.
* `key_id` is public and shows up in logs; on its own it never authenticates.
* The secret is shown once, when the key is created. Store it in your secret manager.

The key goes in the `Authorization: Bearer` header. The SDKs read the `NIADRA_API_KEY` environment variable when you do not pass a key to the constructor.

<CodeGroup>
  ```python Python theme={null}
  from niadra import Niadra

  niadra = Niadra()  # reads NIADRA_API_KEY
  print(niadra.base_url)  # https://acme-prod.us-east-1.api.niadra.com
  ```

  ```typescript TypeScript theme={null}
  import { Niadra } from "@niadra/sdk";

  const niadra = new Niadra(); // reads NIADRA_API_KEY
  ```

  ```bash cURL theme={null}
  curl -X POST "https://acme-prod.us-east-1.api.niadra.com/v1/context" \
    -H "Authorization: Bearer $NIADRA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"subject": {"type": "phone_e164", "value": "+14155550123"}, "view": "chat"}'
  ```
</CodeGroup>

<Warning>
  A source key is a server secret. Never put a key in a browser, a mobile app or a model prompt. To bind a customer to an MCP connection, your backend mints a 15-minute [subject\_token](/en/api/subject-tokens).
</Warning>

## Scopes

Each key has scopes. The route checks the scope before anything else, and a missing scope comes back as 403 with the code `scope_missing`.

| Scope       | What it allows                                                                                                                                                                             |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `track`     | Send messages and system events in the batch, request media uploads, correct the memory                                                                                                    |
| `act`       | Record agent actions, within the `trusted_action_ops` of the source when it has a list                                                                                                     |
| `context`   | Read context and objects, mint `subject_token`                                                                                                                                             |
| `search`    | Search history, read the timeline, open items                                                                                                                                              |
| `identify`  | Send `identify` items in the batch; the `resolve_identity` MCP tool                                                                                                                        |
| `admin`     | Every governance route: identity, erasure, export, receipts, lineage, policy simulation, measurement, triggers, deliveries. The same routes also accept Console people with the right role |
| `analytics` | [Base-wide analysis](/en/api/insights-aggregate), pseudonymous by default. Only sources with the `analyst` audience get it                                                                 |

The `act` scope deserves care. `track` alone does not record actions: an action can close a promise made to a customer, so only a source holding `act` may record it, and a source that declares `trusted_action_ops` (for example only `credit`) records nothing else. It is the first barrier against an action forged through prompt injection. An operation outside the list comes back as an item error with the code `operation_not_allowed`.

When you create a key without naming scopes, it gets the defaults of the source audience: `customer_agent` gets `track`, `context`, `search` and `identify`; `internal_agent` also gets `act`; `human` gets `context` and `search`; `analyst` gets only `analytics`.

A common split:

| Source                         | Scopes                                                                                   |
| ------------------------------ | ---------------------------------------------------------------------------------------- |
| Voice or WhatsApp agent        | `context`, `search`, `track`, `identify`                                                 |
| Internal billing agent         | `context`, `search`, `track`, `act`, with `trusted_action_ops: ["credit"]` on the source |
| CRM or ERP by webhook          | the authentication declared in the source mapping                                        |
| Your team's governance service | `admin`                                                                                  |
| Your BI or analysis LLM        | `analytics`, on a source with the `analyst` audience                                     |

People from your team use the Console with their own token and roles (`admin`, `security`, `integration`, `review`, `analysis`, `vendor`), never a source key. See [Limits and conventions](/en/conventions#authentication).

## Rotate and revoke

[Rotate](/en/api/control/keys-rotate) a key to get a new one with the same scopes; `grace_seconds` (up to 7 days) keeps the old one valid while you roll the new one out through your secret manager. To cut access, [revoke the key](/en/api/control/keys-revoke) or [the whole source](/en/api/control/source-revoke), with a reason, in the Console or through the control API. The revocation reaches every instance of the cell in seconds. The cell also takes a direct cut, [`POST /v1/sources/{source_id}/revoke`](/en/api/source-revoke), for the `security` role: every key of the source stops authenticating there at once.

When a key gets a 401 or 403, the SDK drops the context it held for that key and returns an empty context. That way, cutting a vendor's access also covers what was already in that vendor's cache.

## Next steps

<CardGroup cols={2}>
  <Card title="Events and the batch" href="/en/concepts/events">
    what each source sends and how the batch answers.
  </Card>

  <Card title="Identity and verification" href="/en/concepts/identity">
    handles, profiles and levels V0 to V4.
  </Card>

  <Card title="Limits and conventions" href="/en/conventions">
    versioning, idempotency, rate limits and ETag.
  </Card>

  <Card title="Errors" href="/en/errors">
    the code catalog, including `scope_missing`.
  </Card>
</CardGroup>
