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

# Setting up governance

This guide covers the catalog setup you make as the vendor — both from the Stigg console and via the SDK. Most of these are one-time or infrequent operations; the [Check and Ingest](/documentation/governance/check-and-ingest) calls happen per-request at runtime.

## Via the Stigg console

### Define entity types

In the Stigg app, go to **Governance → Entity types**. The list shows all entity types defined for the environment, along with their attribution keys and the last time each was updated.

<Frame caption="Entity types list">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-entity-types-list.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=d1fdea99bbbde074d5977e6959f47428" alt="Entity types list" width="2880" height="1398" data-path="images/docs/governance-entity-types-list.png" />
</Frame>

Click **+ New entity type** to open the creation drawer.

<Frame caption="New entity type drawer">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-entity-type-new-empty.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=e8930b209469a8d0307fbe83163fc3d1" alt="New entity type — empty" width="2880" height="1398" data-path="images/docs/governance-entity-type-new-empty.png" />
</Frame>

Fill in:

* **Display name** — a human-readable label (e.g. `Organization`). The entity type ID is auto-generated from it and can be edited.
* **Attribution keys** — the dimension keys your usage events carry to identify instances of this type (e.g. `orgId`). Type a key and press Enter to add it; multiple keys are supported.

<Frame caption="Filling in name and attribution key">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-entity-type-new-fill.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=7b481204a308adbe07581b146fd7d4a7" alt="New entity type — filling in" width="2880" height="1398" data-path="images/docs/governance-entity-type-new-fill.png" />
</Frame>

<Frame caption="Attribution key added — ready to create">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-entity-type-new-ready.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=323b0073cfddb1feb7b6998aa308e962" alt="New entity type — ready to create" width="2880" height="1398" data-path="images/docs/governance-entity-type-new-ready.png" />
</Frame>

Once created, the new type appears in the list. Hover a row and click the **⋮** menu to **Edit** it.

<Frame caption="Newly created entity type with edit option">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-entity-type-created.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=b4df12f58f58ff3bded1df1d6797fa47" alt="Entity type created" width="2880" height="1398" data-path="images/docs/governance-entity-type-created.png" />
</Frame>

<Frame caption="Edit entity type drawer">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-entity-type-edit.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=d938fe53d1171e5d2b55bfa9fb802848" alt="Edit entity type" width="2880" height="1398" data-path="images/docs/governance-entity-type-edit.png" />
</Frame>

### View and manage entities for a customer

To view governance data for a specific customer:

1. Go to **Customers → Customer accounts** and open the customer record.

<Frame caption="Customer accounts list">
  <img src="https://mintcdn.com/stigg/RjVKlcnBc3TW7R6e/images/docs/governance-customer-accounts-list.png?fit=max&auto=format&n=RjVKlcnBc3TW7R6e&q=85&s=e42d0ed509242c9cda4deebdc0abaf97" alt="Customer accounts list" width="2880" height="1398" data-path="images/docs/governance-customer-accounts-list.png" />
</Frame>

2. Click the **Governance** tab.

The tab shows the customer's entity hierarchy on the left, their entity types in the **Type** column, and — for each entitlement — the current usage vs. limit broken out by scope (Node-wide and per-model or other dimension).

<Frame caption="Customer Governance tab — entity hierarchy with usage">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-customer-tab-overview.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=f4a54aa7e6ec6830f6552c3b7fff5169" alt="Customer Governance tab overview" width="2880" height="1398" data-path="images/docs/governance-customer-tab-overview.png" />
</Frame>

### Sort and prioritize entities

Use the **Order by** control (the sliders icon next to the type filter) to rank entities by consumption. Two modes are available:

* **Usage** — ranks by absolute consumption, so the heaviest consumers appear first
* **Utilization** — ranks by percentage of limit used, so entities closest to being blocked surface first

<Frame caption="Order by — Usage vs. Utilization">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-customer-sort-order.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=38cdbd36e514f52f6323a2106395100d" alt="Sort order panel" width="1466" height="416" data-path="images/docs/governance-customer-sort-order.png" />
</Frame>

Switching to **Utilization** is the fastest way to spot entities that are about to hit their limit and may need a budget increase or intervention before they get blocked.

### Add an entity to a customer

Click **+ Add entity** to open the drawer.

<Frame caption="Add entity drawer — empty">
  <img src="https://mintcdn.com/stigg/RjVKlcnBc3TW7R6e/images/docs/governance-customer-add-entity-empty.png?fit=max&auto=format&n=RjVKlcnBc3TW7R6e&q=85&s=af10069cd6ae9dbd4c2f2c1a8cae9e8c" alt="Add entity — empty" width="2880" height="1398" data-path="images/docs/governance-customer-add-entity-empty.png" />
</Frame>

Fill in:

* **Entity ID** — the unique identifier used in API calls (e.g. `org-acme`)
* **Entity type** — select from the entity types defined for this environment

<Frame caption="Selecting an entity type">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-customer-add-entity-type.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=0d46f299e13401b653ba8c6e7aaa7cc3" alt="Add entity — entity type dropdown" width="2880" height="1398" data-path="images/docs/governance-customer-add-entity-type.png" />
</Frame>

* **Parent entity** *(optional)* — place this entity under a parent in the hierarchy (e.g. nest a user under a team)

<Frame caption="Selecting a parent entity">
  <img src="https://mintcdn.com/stigg/RjVKlcnBc3TW7R6e/images/docs/governance-customer-add-entity-parent.png?fit=max&auto=format&n=RjVKlcnBc3TW7R6e&q=85&s=12f5b416e9ec43a4758cf4b0356f53b1" alt="Add entity — parent selected" width="2880" height="1398" data-path="images/docs/governance-customer-add-entity-parent.png" />
</Frame>

* **Cardinality** *(optional)* — restrict this entity's budget to a specific sub-context by selecting entities to slice by

<Frame caption="Cardinality — selecting entities to slice by">
  <img src="https://mintcdn.com/stigg/RjVKlcnBc3TW7R6e/images/docs/governance-customer-add-entity-cardinality.png?fit=max&auto=format&n=RjVKlcnBc3TW7R6e&q=85&s=d0a8a9e3ff7e430f070ce261c5f886cd" alt="Add entity — cardinality dropdown" width="2880" height="1398" data-path="images/docs/governance-customer-add-entity-cardinality.png" />
</Frame>

After adding entities, the full hierarchy is visible in the Governance tab with all entitlement columns.

<Frame caption="Full governance hierarchy with all entities and entitlement columns">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-customer-hierarchy-full.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=8ae3e9b3acea59fed8c324172621267c" alt="Full governance hierarchy" width="2880" height="1398" data-path="images/docs/governance-customer-hierarchy-full.png" />
</Frame>

### Edit an entitlement value inline

Click any entitlement cell in the Governance tab to edit the limit value inline, then confirm with the checkmark.

<Frame caption="Inline editing an entitlement value">
  <img src="https://mintcdn.com/stigg/_TNIA08bS1sdXVQ5/images/docs/governance-customer-inline-edit.png?fit=max&auto=format&n=_TNIA08bS1sdXVQ5&q=85&s=0793eb7c5c36f3c4e0903358f1d43a02" alt="Inline edit entitlement" width="2880" height="1398" data-path="images/docs/governance-customer-inline-edit.png" />
</Frame>

***

## Via the SDK

### Installation

<CodeGroup>
  ```shell npm theme={null}
  npm install @stigg/governance-client
  ```

  ```shell yarn theme={null}
  yarn add @stigg/governance-client
  ```
</CodeGroup>

### Initializing the client

Create one client instance per process and reuse it across your codebase.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { createGovernanceClient } from '@stigg/governance-client';

  const governance = createGovernanceClient({
    baseUrl:       process.env.GOVERNANCE_API_URL,
    accessToken:   process.env.GOVERNANCE_ACCESS_TOKEN,
    accountId:     process.env.STIGG_ACCOUNT_ID,
    environmentId: process.env.STIGG_ENVIRONMENT_ID,
    caller:        'my-app',
  });
  ```
</CodeGroup>

| Option          | Description                                                  |
| --------------- | ------------------------------------------------------------ |
| `baseUrl`       | Base URL of the Governance API                               |
| `accessToken`   | Static Bearer token for server-to-server auth                |
| `auth`          | M2M client-credentials config (alternative to `accessToken`) |
| `accountId`     | Your Stigg account ID                                        |
| `environmentId` | The target environment ID                                    |
| `caller`        | Identifier for the calling service, used in logs             |

The client exposes six namespaces: `governance.entityTypes`, `governance.entities`, `governance.capabilities`, `governance.assignments`, `governance.check`, `governance.ingest`.

Every method returns an Axios response — access `.data` to get the payload.

***

## Step 1 — Define entity types

Entity types are the categories of resource you want to govern (e.g., `org`, `team`, `user`, `agent`). Define them once per environment. The `attributionKeys` are the dimension keys your ingest events carry to identify instances of each type.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { data: entityTypes } = await governance.entityTypes.entityTypeControllerUpsert({
    types: [
      { id: 'org',   displayName: 'Organization', attributionKeys: ['orgId'] },
      { id: 'team',  displayName: 'Team',         attributionKeys: ['teamId'] },
      { id: 'user',  displayName: 'User',         attributionKeys: ['userId'] },
      { id: 'agent', displayName: 'AI agent',     attributionKeys: ['agentId'] },
    ],
  });
  // entityTypes: EntityTypeResponse[]
  ```

  ```bash curl theme={null}
  curl -X PUT https://<GOVERNANCE_API_URL>/entity-types \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>" \
    -H "Content-Type: application/json" \
    -d '{
      "types": [
        { "id": "org",   "displayName": "Organization", "attributionKeys": ["orgId"] },
        { "id": "team",  "displayName": "Team",         "attributionKeys": ["teamId"] },
        { "id": "user",  "displayName": "User",         "attributionKeys": ["userId"] },
        { "id": "agent", "displayName": "AI agent",     "attributionKeys": ["agentId"] }
      ]
    }'
  ```
</CodeGroup>

The upsert is **idempotent** — re-submitting the same payload is safe. Up to 100 types per request.

**Response** (`200 OK`):

```json theme={null}
[
  {
    "id": "org",
    "displayName": "Organization",
    "attributionKeys": ["orgId"],
    "createdAt": "2026-01-15T10:00:00.000Z",
    "updatedAt": "2026-01-15T10:00:00.000Z"
  }
]
```

### Listing entity types

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { data } = await governance.entityTypes.entityTypeControllerList(
    undefined, // after cursor
    undefined, // before cursor
    20,        // limit
  );
  // data.data: EntityTypeResponse[]
  // data.pagination: { next, prev }
  ```

  ```bash curl theme={null}
  curl "https://<GOVERNANCE_API_URL>/entity-types?limit=20" \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>"
  ```
</CodeGroup>

***

## Step 2 — Define capabilities

Capabilities are the metered resources you track (e.g., `api-calls`, `ai-tokens`, `seats`). All capabilities are of type `METER` in V1.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { data: capabilities } = await governance.capabilities.capabilityControllerUpsert({
    capabilities: [
      { id: 'api-calls', type: 'METER' },
      { id: 'ai-tokens', type: 'METER' },
      { id: 'seats',     type: 'METER' },
    ],
  });
  ```

  ```bash curl theme={null}
  curl -X PUT https://<GOVERNANCE_API_URL>/capabilities \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>" \
    -H "Content-Type: application/json" \
    -d '{
      "capabilities": [
        { "id": "api-calls", "type": "METER" },
        { "id": "ai-tokens", "type": "METER" }
      ]
    }'
  ```
</CodeGroup>

**Response** (`200 OK`):

```json theme={null}
[
  {
    "id": "api-calls",
    "type": "METER",
    "createdAt": "2026-01-15T10:00:00.000Z",
    "updatedAt": "2026-01-15T10:00:00.000Z"
  }
]
```

### Fetching a single capability

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { data: capability } = await governance.capabilities.capabilityControllerGet('api-calls');
  ```

  ```bash curl theme={null}
  curl "https://<GOVERNANCE_API_URL>/capabilities/api-calls" \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>"
  ```
</CodeGroup>

***

## Step 3 — Provision entities per customer

When a customer creates an org, team, or user in your product, provision the corresponding entity in governance. The `ownerId` is the customer's ID in your system.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const customerId = 'cus-acme';

  const { data: entities } = await governance.entities.entityControllerUpsert(customerId, {
    entities: [
      { id: 'org-acme',     typeRefId: 'org',   metadata: { plan: 'enterprise' } },
      { id: 'team-eng',     typeRefId: 'team' },
      { id: 'team-product', typeRefId: 'team' },
      { id: 'agent-claude', typeRefId: 'agent' },
    ],
  });
  ```

  ```bash curl theme={null}
  curl -X PUT https://<GOVERNANCE_API_URL>/owners/cus-acme/entities \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>" \
    -H "Content-Type: application/json" \
    -d '{
      "entities": [
        { "id": "org-acme",     "typeRefId": "org",   "metadata": { "plan": "enterprise" } },
        { "id": "team-eng",     "typeRefId": "team" },
        { "id": "team-product", "typeRefId": "team" },
        { "id": "agent-claude", "typeRefId": "agent" }
      ]
    }'
  ```
</CodeGroup>

Up to 100 entities per request. Idempotent — safe to re-run during re-syncs.

**Metadata patch semantics**: keys present in `metadata` are merged over existing values. Set a key to `""` to delete it. Omitting `metadata` entirely leaves the stored metadata unchanged.

**Response** (`200 OK`):

```json theme={null}
[
  {
    "id": "org-acme",
    "typeId": "org",
    "metadata": { "plan": "enterprise" },
    "archivedAt": null,
    "createdAt": "2026-01-15T10:00:00.000Z",
    "updatedAt": "2026-01-15T10:00:00.000Z"
  }
]
```

### Listing entities

<CodeGroup>
  ```typescript TypeScript theme={null}
  // All active entities for the customer
  const { data } = await governance.entities.entityControllerList('cus-acme');

  // Filter by entity type
  const { data: teams } = await governance.entities.entityControllerList(
    'cus-acme',
    undefined, // after
    undefined, // before
    20,        // limit
    'team',    // refId (type filter)
  );

  // Include archived
  const { data: all } = await governance.entities.entityControllerList(
    'cus-acme',
    undefined, undefined, 20,
    undefined,
    'true', // includeArchived
  );
  ```

  ```bash curl theme={null}
  # All active entities
  curl "https://<GOVERNANCE_API_URL>/owners/cus-acme/entities?limit=20" \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>"
  ```
</CodeGroup>

### Getting a single entity

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { data: entity } = await governance.entities.entityControllerGet('cus-acme', 'org-acme');
  ```

  ```bash curl theme={null}
  curl "https://<GOVERNANCE_API_URL>/owners/cus-acme/entities/org-acme" \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>"
  ```
</CodeGroup>

### Archiving and unarchiving entities

Archiving is a soft-delete: the entity disappears from the list but remains accessible via GET-by-ID.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Archive
  await governance.entities.entityControllerArchive('cus-acme', { ids: ['team-old-project'] });

  // Unarchive
  await governance.entities.entityControllerUnarchive('cus-acme', { ids: ['team-old-project'] });
  ```

  ```bash curl theme={null}
  # Archive
  curl -X POST https://<GOVERNANCE_API_URL>/owners/cus-acme/entities/archive \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>" \
    -H "Content-Type: application/json" \
    -d '{ "ids": ["team-old-project"] }'
  ```
</CodeGroup>

Both return `204 No Content`.

***

## Step 4 — Create assignments

Assignments set the usage limit for an `(entity, capability)` pair — they are the governance equivalent of entitlements, and appear as entitlement columns in the Stigg console's Governance tab. They are typically created by your customers through an in-app interface, but you can also set them programmatically.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { data: assignments } = await governance.assignments.assignmentControllerUpsert('cus-acme', {
    assignments: [
      {
        entityId:     'org-acme',
        capabilityId: 'ai-tokens',
        usageLimit:   1_000_000,
        cadence:      'P1M',
      },
      {
        entityId:     'team-eng',
        capabilityId: 'ai-tokens',
        parentId:     'org-acme',   // places team-eng under org-acme in the hierarchy
        usageLimit:   200_000,
        cadence:      'P1M',
      },
    ],
  });
  ```

  ```bash curl theme={null}
  curl -X PUT https://<GOVERNANCE_API_URL>/owners/cus-acme/assignments \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>" \
    -H "Content-Type: application/json" \
    -d '{
      "assignments": [
        {
          "entityId": "org-acme",
          "capabilityId": "ai-tokens",
          "usageLimit": 1000000,
          "cadence": "P1M"
        },
        {
          "entityId": "team-eng",
          "capabilityId": "ai-tokens",
          "parentId": "org-acme",
          "usageLimit": 200000,
          "cadence": "P1M"
        }
      ]
    }'
  ```
</CodeGroup>

**Patch semantics**: on re-upsert, omitting `usageLimit` or `cadence` preserves the existing value. On first create, both are required.

**`usageLimit: null` — tracked but unlimited**: setting `usageLimit` to `null` means usage is still counted and appears in check responses, but the limit never blocks. Useful for observability before enforcing.

**Response** (`200 OK`):

```json theme={null}
[
  {
    "id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "entityId": "org-acme",
    "capabilityId": "ai-tokens",
    "scopeEntityIds": [],
    "usageLimit": 1000000,
    "cadence": "P1M",
    "parentId": null,
    "createdAt": "2026-01-15T10:00:00.000Z",
    "updatedAt": "2026-01-15T10:00:00.000Z"
  }
]
```

### Hierarchy — placing entities in a tree

The `parentId` field places an entity under a parent in the governance hierarchy. The check endpoint evaluates every budget in the chain from the target entity to the root — a request is only granted when all budgets along the path allow it.

<Note>
  `parentId` is tri-state: **omitting** it leaves the current parent unchanged (new nodes default to root); **`null`** detaches the entity to root; a **refId** sets or changes the parent. Reparenting is only allowed for leaf nodes — a node with children cannot be moved.
</Note>

### Dimension-scoped sub-budgets

Add a tighter budget for a specific context by setting `scopeEntityIds`. The scoped budget applies only when every listed entity is present in the resolved set for the request.

<CodeGroup>
  ```typescript TypeScript theme={null}
  await governance.assignments.assignmentControllerUpsert('cus-acme', {
    assignments: [
      // Node-wide budget — always applies
      { entityId: 'team-eng', capabilityId: 'ai-tokens', scopeEntityIds: [],             usageLimit: 200_000, cadence: 'P1M' },
      // Tighter budget — applies only when model-gpt4o is in the request context
      { entityId: 'team-eng', capabilityId: 'ai-tokens', scopeEntityIds: ['model-gpt4o'], usageLimit: 10_000,  cadence: 'P1M' },
    ],
  });
  ```
</CodeGroup>

### Listing assignments

<CodeGroup>
  ```typescript TypeScript theme={null}
  // All assignments for the customer
  const { data } = await governance.assignments.assignmentControllerList('cus-acme');

  // Filter by entity
  const { data: byEntity } = await governance.assignments.assignmentControllerList(
    'cus-acme',
    undefined, undefined, 20,
    'team-eng', // entityId filter
  );

  // Filter by capability
  const { data: byCap } = await governance.assignments.assignmentControllerList(
    'cus-acme',
    undefined, undefined, 20,
    undefined,
    'ai-tokens', // capabilityId filter
  );
  ```

  ```bash curl theme={null}
  curl "https://<GOVERNANCE_API_URL>/owners/cus-acme/assignments?entityId=team-eng" \
    -H "Authorization: Bearer <ACCESS_TOKEN>" \
    -H "x-stigg-account-id: <ACCOUNT_ID>" \
    -H "x-stigg-environment-id: <ENVIRONMENT_ID>"
  ```
</CodeGroup>

## What's next

<CardGroup cols={2}>
  <Card title="Check and ingest" icon="bolt" href="/documentation/governance/check-and-ingest">
    Gate access before consumption and record usage after
  </Card>

  <Card title="Query the governance tree" icon="chart-bar" href="/documentation/governance/query">
    Fetch usage and budget data for dashboards and admin UIs
  </Card>
</CardGroup>
