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

# Set up agent identity governance: inventory, sponsors, and bulk decommission

> Walk the full non-human-identity (NHI) sequence with worked cURL — inventory every AI agent, confirm its human sponsor and per-channel reach, bulk-suspend a selection with a safe rollback, and alert on identities that drift out of sponsorship.

# Set up agent identity governance: inventory, sponsors, and bulk decommission

Every AI agent you create is a non-human identity (NHI): it has a
lifecycle, it has a human sponsor, and it has per-channel limits on
what it can reach. This guide walks the four-step sequence an access
review actually runs — **inventory → sponsor → reach → decommission** —
with the exact request and response at each step, no code required.

<Warning>
  Agent identity governance is a **tenant-owned** control, per the
  [posture overview](/compliance/posture-overview). Whether your
  organization needs an NHI inventory, and how often you decommission,
  depends on your policy and your counsel. Orbit ships the surface and
  the audit trail; you own the decision.
</Warning>

## What an AI-agent NHI is

The Cloud Security Alliance's NHI framework asks a security team to
answer, on demand: which agent identities exist, who sponsors each one,
what can each one touch, and can you stop them all right now. Each
Orbit agent carries the inputs for those answers:

1. **Lifecycle.** A created agent starts in `draft`. Promoting it to
   `active` puts it in service — routed traffic reaches it. Suspending
   it takes it out of service: `suspended` agents stop receiving
   traffic, but nothing is deleted and recordings, history, and spend
   attribution are preserved. Suspension is reversible; deletion is
   not the decommission path.
2. **Sponsor.** Every agent row stamps the human who created it. That
   sponsor id is attributed in the inventory and resolved to the member
   roster. When the sponsor leaves, the id stays on the row — a
   null-resolving sponsor is a review finding, not missing data.
3. **Reach.** Per-channel concurrency caps bound what the agent can
   touch right now, per channel. A missing cap fails open (no limit);
   a cap of `0` blocks the agent on that channel outright.

The dashboard inventory surfaces all three; the SCIM
[/Agents resource](/compliance/scim-provisioning) is the IdP-driven
half of the same lifecycle, and both read the same agents table.

## The inventory surface

In the dashboard, open **Settings → Agent identities**: one row per
agent in your organization, with a lifecycle-status filter, a sponsor
filter, and a search box. The same surface is callable as
`GET /api/v1/settings/agent-identities` for audit tooling.

Two access rules apply to every request on this surface:

* **Scope + role.** Reads require the `agents:read` scope; writes
  require `agents:write`. Both also require the **owner/admin** role —
  decommissioning an identity estate is never a self-service action.
* **Organization scope.** You only ever see your own organization's
  agents and your own member roster.

## Enumerate the inventory

Page through the inventory and filter it to the estate you are
auditing. The query accepts `status`, `sponsorId`, a case-insensitive
`search` over name and description, plus `page` / `pageSize`
(`pageSize` caps at 100).

```bash theme={null}
curl -X GET \
  "https://api.orbit.devotel.io/api/v1/settings/agent-identities?status=active&pageSize=100" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Each row in `data` carries:

| Field | Meaning |
| - | - |
| `id` | Opaque agent identity id — the value you pass back to decommission. |
| `name`, `description` | Display name and free-text description you set. |
| `type` | Agent type. |
| `status` | Lifecycle status: `draft`, `active`, or `suspended`. |
| `active` | Boolean projection — `true` unless `status` is `suspended`. Matches the SCIM `active` flag exactly. |
| `sponsor` | The human sponsor resolved to `{ id, name, email }` from your member roster, or `null`. |
| `createdAt`, `updatedAt` | Creation and last-modified timestamps. |
| `channelCaps` | Per-channel reach — a list of `{ channel, maxConcurrent }`. An empty list means no caps are set (fail-open). |

A typical row:

```json theme={null}
{
  "id": "agent-abc123",
  "name": "Collections outreach",
  "description": "Outbound collections agent, EN",
  "type": "outbound",
  "status": "active",
  "active": true,
  "sponsor": { "id": "user_2xK9...", "name": "M. Ruiz", "email": "m.ruiz@example.com" },
  "createdAt": "2026-04-11T09:14:02.000Z",
  "updatedAt": "2026-09-02T17:41:19.000Z",
  "channelCaps": [
    { "channel": "voice", "maxConcurrent": 25 },
    { "channel": "sms", "maxConcurrent": 100 }
  ]
}
```

The `sponsor` resolves to `null` when the agent predates sponsor
stamping (rare) — treat it as a review finding. A sponsor id whose
member left the roster still returns the id with an empty name and
email, so attribution survives off-boarding.

## Assign and review human sponsors

Sponsorship is recorded at creation time — the person who creates the
agent is its sponsor. Reviewing sponsors is the second step of the
sequence:

1. Pull the inventory and group rows by `sponsor.id`.
2. Confirm each sponsor is still an active member of your
   organization. A sponsor id that resolves with an empty `name` and
   `email` means the member has left the roster — the attribution
   stays, but someone currently in the org should own the agent.
3. Where an agent's sponsor no longer makes sense — the member left,
   the project moved teams — reassign ownership by recreating or
   re-pointing the agent under the new owner. There is no sponsor-edit
   endpoint; sponsorship follows creation.

## Per-channel reach settings

`channelCaps` on each row is what the agent can reach right now. Use
it as a review checklist:

* **No cap listed → no limit.** A missing channel fails open; the
  agent has no concurrency bound on that channel.
* **`maxConcurrent: 0` → blocked.** The agent cannot run on that
  channel at all.
* **Anything in between → bounded concurrency.**

Flag rows whose reach exceeds what the sponsor intended — an agent
with an uncapped `voice` channel and a collections-script description
is exactly the finding a CSA-style review looks for.

## Bulk suspend and reactivate

When the review decides an agent (or the estate) comes out of
service, suspend it — never delete it. Bulk suspension is one call:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/agent-identities/bulk-suspend" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["agent-abc123", "agent-def456"] }'
```

Response:

```json theme={null}
{
  "data": {
    "updated": ["agent-abc123"],
    "notFound": ["agent-def456"],
    "count": 1
  }
}
```

The contract that makes this a safe review action:

* **Bounded per call.** Up to 500 explicit ids, or `{ "all": true }`
  to suspend the entire inventory at once.
* **Idempotent.** Re-suspending an already-suspended agent is a no-op;
  re-running the same body returns a stable response.
* **Mis-targets are reported, not dropped.** Any id your organization
  does not own — or that simply does not exist — comes back in
  `notFound`, so a typo never silently skips an agent. Check
  `notFound` on every run.
* **Audited.** Every bulk suspend writes to your organization's audit
  log with the requested ids, the ids actually suspended, and the
  not-found set.

**Safe rollback flow.** Suspension is the rollback, not a one-way
door:

1. Suspend the selection and confirm `notFound` is empty.
2. Verify the agents are out of service — re-run the inventory with
   `status=suspended` and confirm the ids are there.
3. If the suspension turns out to be wrong, reactivate each agent
   through the agent management surface (set its lifecycle back to
   `active`). Recordings, conversation history, and spend attribution
   are untouched by the suspend, so a reactivated agent returns to
   service whole.

There is no bulk-reactivate endpoint — reactivation is deliberate and
per-agent, which is the posture an access review expects: tear-down is
bulk, restoration is inspected.

To decommission the whole estate at once:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/agent-identities/bulk-suspend" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "all": true }'
```

## Alert on drifted identities

The inventory is also the signal source for ongoing monitoring. Two
conditions are worth a scheduled check against your alerting stack:

* **Un-sponsored identities.** Pull the full inventory and alert on
  any row whose `sponsor` is `null`, or whose `sponsor.id` no longer
  resolves to a current member (empty `name`/`email`). Each drifted
  agent is an identity with no accountable human — the exact row a
  CSA review asks you to explain.
* **Reach wider than intent.** Alert on rows where `channelCaps` is
  empty (no cap on any channel) for agents that should be bounded, or
  where a cap you expect is missing.

Run the check on a cadence that matches your review policy — daily for
a regulated estate, weekly otherwise — and page the owning team, not
Orbit: the control is tenant-owned, and so is its observability.

## Related

* [Agent identity governance (compliance reference)](/compliance/agent-identity-governance) —
  the control surface this walk-through exercises.
* [SCIM provisioning](/compliance/scim-provisioning) — the IdP-driven
  half of the same NHI lifecycle.
* [Authorization mandates](/agents/authorization-mandates) — scoped,
  expiring mandate detail on top of the identity.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.