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

# Register an agent

> Register the requesting agent in the BotShield Console, choose the action categories it may propose, and copy its agent key.

Every Agents Ask call is made by a registered agent. Registering one in the BotShield Console gives you an **agent key**, fixes the name your users see on every card, and declares which kinds of action the agent may propose. Registration is self-serve at [console.botshield.ai](https://console.botshield.ai).

## Register the agent

<Steps>
  <Step title="Open Trusted Agents">
    In the BotShield Console, go to **Agents Ask → Trusted Agents**. The page has four tabs: **Trusted Agents**, **Resolutions**, **Sandbox**, and **Plan**.
  </Step>

  <Step title="Pick the environment">
    Use the **Development | Production** toggle in the page header. The agent is created in the environment that is selected, and it cannot be moved later. Start in **Development**.
  </Step>

  <Step title="Click Register Agent and fill in the form">
    | Field | Rules | Notes |
    | - | - | - |
    | **Agent name** | Letters and digits only. Starts with a letter. 2–32 characters. | Becomes part of the key. Must be unique among your active agents in that environment. Example: `MeridianConcierge`. |
    | **Display name** | 1–64 characters. | The friendly name shown to your users on every card. Example: `Meridian Airlines Concierge`. |
    | **Allowed action categories** | Comma-separated. 1 to 20 categories. | The only categories this agent may propose. See [Action categories](#action-categories). |
  </Step>

  <Step title="Click Register and copy the key">
    The Console shows the agent key once. Copy it into your secret store before you click **Done**.
  </Step>
</Steps>

<Warning>
  The agent key is shown **only once**. BotShield keeps a hash of it, not the key, so nobody can show it to you again. If you lose it, [rotate the key](#rotate-a-key) to get a new one.
</Warning>

After you click **Done**, the agent appears in the **Trusted Agents** list with its display name, its agent name, its **Agent ID**, its allowed categories, and an **Active** status. Each active row has three actions: **Edit**, **Rotate key**, and **Revoke**.

## The agent key

```text theme={null}
bs_agent_<AgentName>__<secret>
```

* `<AgentName>` is the agent name you entered. `<secret>` is a random 43-character string.
* Send it as a Bearer token on every Agents Ask call: `Authorization: Bearer bs_agent_MeridianConcierge__…`.
* It is a server-side secret. Never ship it in a browser, a mobile app, or a prompt.
* A key belongs to one agent in one environment.

If a name is already in use, registration fails with the code `agent_name_taken`. Choose another name, or revoke the existing agent first.

## The Agent ID

Every agent also has an **Agent ID**, a UUID that BotShield assigns at registration. It is shown on the agent's row in **Trusted Agents**, under the agent name, with a copy button next to it.

```text theme={null}
a9f2c6d4-1b7e-4f3a-9c58-2e6d0b4a7f11
```

* The Agent ID is the `aud` claim of every [Proof of Resolution](/agents-ask/proof-of-resolution) issued for this agent. Copy it into your configuration next to the agent key, and pin the audience check to it.
* It is an identifier, not a secret. It also appears as `agent_id` in the `agents_ask.*` [webhook events](/webhooks/events).
* It never changes, including when you rotate the key. A development agent and a production agent have different Agent IDs, even when they share a name.

## Action categories

A category is a short label for a kind of action, in `domain.verb` form. You choose your own categories; there is no fixed list to pick from. BotShield enforces them per agent: a proposal whose `action.category` is not in the agent's list is rejected with a 403 error. See [Propose an action](/agents-ask/propose-an-action#errors).

Format rules for each category:

* Starts with a lowercase letter.
* Then 1 to 40 more characters from lowercase letters, digits, `.`, `_`, and `-`.

Examples: `travel.book`, `travel.refund`, `payment.authorize`, `account.update`.

To change an agent's categories later, click **Edit** on its row in **Trusted Agents**, update the comma-separated list, and click **Save**. At least one category is required.

<Tip>
  Keep categories narrow. An agent that only issues refunds should hold `travel.refund` and nothing else, so a compromised prompt cannot make it propose a payment.
</Tip>

## Development and production agents

| | Development | Production |
| - | - | - |
| Who can register an agent or rotate its key | Any Console admin | A Console admin who confirms with a **console passkey** |
| Where the key works | The [Sandbox tester](#test-in-the-sandbox) in the Console | `https://api.botshield.ai/operations` and `https://mcp.botshield.ai/mcp` |
| Same name allowed in both | Yes. Names are unique per environment. | |

Each environment's API accepts only its own agents. The production API rejects a development key with a 401 error whose message reads `Trusted agent "MeridianConcierge" exists but is registered for development; this endpoint is production.`

### Production requires a console passkey

When the header toggle is on **Production**:

1. If your Console account has no passkey yet, **Register Agent** first asks you to create one.
2. When you click **Register**, the Console asks you to confirm with that passkey. The confirmation must be recent; if it is declined or cancelled, nothing is created.

**Rotate key** on a production agent asks for the same passkey confirmation, because it issues a new production credential.

Development agents need no passkey.

## Rotate a key

Rotate a key when it may have been exposed, when someone who had it leaves, or on your own schedule. Rotation replaces the secret and keeps the agent: its agent name, display name, [Agent ID](#the-agent-id), and allowed categories stay the same. The people who linked to the agent stay linked, and proposals that are waiting for a decision stay open.

<Steps>
  <Step title="Click Rotate key">
    In **Agents Ask → Trusted Agents**, click **Rotate key** on the agent's row. The Console asks you to confirm: `Rotate the production key for "Meridian Airlines Concierge"? The current key stops working immediately.`
  </Step>

  <Step title="Confirm with your passkey (Production only)">
    For a production agent, the Console asks you to confirm with your console passkey. If your account has no passkey yet, it asks you to create one first and then continues. If you cancel or decline the passkey prompt, nothing changes and the current key keeps working. Development agents skip this step.
  </Step>

  <Step title="Copy the new key">
    A **New agent key for …** panel appears above the agent list with the new key and a **Copy** button. The key is shown once. Copy it into your secret store before you leave the page.
  </Step>
</Steps>

<Warning>
  The previous key stops working the moment the new one is issued. There is no overlap period. Calls that still send the old key fail with a 401 error until you deploy the new one, so have the change to your secret store ready before you rotate.
</Warning>

A revoked agent cannot be rotated. Register a new agent instead.

## Revoke an agent

Click **Revoke** on the agent's row and confirm. Revocation is permanent and takes effect immediately: the next call with that key fails with a 401 error and the message `Trusted agent "…" has been revoked.` A revoked agent cannot be restored, and its key cannot be rotated. The name becomes available again once the agent is revoked, so you can register a new agent under it. The new agent has a new key and a new Agent ID.

To replace a key and keep the agent, use [Rotate a key](#rotate-a-key) instead.

## Test in the Sandbox

**Agents Ask → Sandbox** opens the **Agents Ask Tester**. It fires a real proposal to a real phone on behalf of one of your **development** agents, so you can see the whole loop before you write code. You do not paste a key; the Console acts as the agent you select.

<Steps>
  <Step title="Select a development agent">
    The picker lists only development agents and shows each agent's allowed categories.
  </Step>

  <Step title="Step 1 · Link with BotShield">
    Click **Create link code**. In the BotShield app on your phone, go to **Account → BotShield Agent → Link with an agent**, enter the 6-character code, and confirm with your biometric. The **Opaque ID** appears in the tester and pre-fills the next step. Codes last 10 minutes.
  </Step>

  <Step title="Step 2 · Build the card">
    Choose an **Action category**, then set the **Summary title**, optional **Detail label** and **Detail value**, **TTL seconds** (60–86400, default 600), and an optional **Adaptive Card payload**. **Load demo** fills in a sample payload. The **Preview** tab renders the card as your user will see it.
  </Step>

  <Step title="Fire test action">
    Your phone receives the card. Confirm or Deny it. The **Result** panel polls every 2 seconds and shows the status, timestamps, and the signed Proof of Resolution when the decision lands.
  </Step>
</Steps>

Sandbox proposals behave like API proposals: they send a real push, appear under **Resolutions**, and emit the `agents_ask.*` [webhook events](/webhooks/events) to your configured endpoints.

The panel to the right of the form has three tabs. **Preview** renders the card. **TypeScript SDK** and **cURL** show the `agentlink/inquire` call for the card you built, with your values filled in and a placeholder where the agent key goes. The TypeScript snippet is written for `botshield-sdk` 2.0.0: it passes `serverURL`, sends the key as `Bearer …` through `security.agentKeyAuth`, uses the camelCase request fields, and checks `result.data.error` before it reads the result. It matches the samples in [Propose an action](/agents-ask/propose-an-action), so you can paste it into your project and supply the key from your secret store.

## Review activity

The **Resolutions** tab lists every proposal for the selected environment, 50 to a page, with the columns **Time Stamp**, **Agent**, **Action**, **Category**, and **Verdict**. The **Verdict** column uses the display words, not the wire values:

| Verdict shown | API `status` |
| - | - |
| **Confirmed** | `approved` |
| **Denied** | `denied` |
| **Expired** | `expired` |
| **Cancelled** | `cancelled` |
| **Pending** | `queued` |

The tester's **Result** panel shows the API `status` value as it is on the wire, for example `approved`.

## Next steps

<CardGroup cols={2}>
  <Card title="Link a human" icon="link" href="/agents-ask/link-a-human">
    Get the `opaque_id` your agent will propose to.
  </Card>

  <Card title="Propose an action" icon="paper-plane" href="/agents-ask/propose-an-action">
    Call the API with your new agent key.
  </Card>

  <Card title="Keys and environments" icon="key" href="/console/keys-and-environments">
    How agent keys sit alongside site keys and API keys.
  </Card>

  <Card title="Hosted MCP server" icon="plug" href="/agents-ask/mcp-server">
    Give the same key to an MCP-capable agent.
  </Card>
</CardGroup>
