# Agent routes: teach, upgrade

URL: /code/api/agent/verbs-teach · Id: `page:code/api/agent/verbs-teach`

> The Agent Verbs teach, upgrade as api.sb routes, with inputs, result, refusals and an example.

Reference for [Agent](/business/nouns/agent), one group of [Agent routes](/code/api/agent).

### Agent.teach
Teach adds a rule to a Customer’s own minted Agent that binds only that Customer’s Tenant. [Verb page](/business/nouns/agent/teach?interface=api).

```text
POST /{namespace}/agents/{agent}/teach
```

Path: `agent`. Body, as JSON: the other inputs. Emits [`Agent.taught`](/business/events/Agent.taught).

**Inputs**

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `agent` | [Agent](/business/nouns/agent) | Yes | The minted Agent. |
| `rule` | `text` | Yes | The rule, in plain words. |
| `case` | `text` | Yes | A case the rule must pass, kept with the Tenant’s cases. |

**Returns**

| Output | Type | Required | Description |
| --- | --- | --- | --- |
| `agent` | [Agent](/business/nouns/agent) | Yes | The Agent with the rule. |

**Refuses when**

| Check | Error | Fix | Then call |
| --- | --- | --- | --- |
| The key is valid, but its scopes do not allow this operation | [`forbidden`](/code/api/errors/forbidden) | Use a key whose scopes cover the operation, or ask an owner of the namespace to grant them. | None. |
| A rule that would widen what the product’s Role contract allows | [`refused`](/code/api/errors/refused) | Clear what the check names, then call it again. | None. |
| `agent` is missing, or is not a agent | [`invalid-input`](/code/api/errors/invalid-input) | Send `agent` as a agent, then call it again. | None. |
| `rule` is missing, or is not a text | [`invalid-input`](/code/api/errors/invalid-input) | Send `rule` as a text, then call it again. | None. |
| `case` is missing, or is not a text | [`invalid-input`](/code/api/errors/invalid-input) | Send `case` as a text, then call it again. | None. |
| The `Idempotency-Key` was sent before with another operation or other input | [`idempotency-mismatch`](/code/api/errors/idempotency-mismatch) | Send a new key for new input; reuse a key only to retry the same request. | None. |

**Example**

```bash
curl -X POST https://api.sb/leaseline.app/agents/agent_tCzKDMorKn/teach \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Idempotency-Key: leaseline-agent-teach-1" \
  -H "Content-Type: application/json" \
  -d '{"rule":"Example rule","case":"Example case"}'
```

```json
{
  "api": "https://api.sb/leaseline.app",
  "agent": {
    "$id": "https://api.sb/leaseline.app/agents/agent_tCzKDMorKn",
    "$type": "Agent",
    "instructions": "Write as the property manager’s assistant. Never promise a rent the manager has not set.",
    "model": "claude-opus-5-5",
    "status": "seated"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/act_br07HsG8MG",
    "operation": "Agent.teach",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/act_br07HsG8MG"
  }
}
```

### Agent.upgrade
Upgrade moves a Customer’s minted Agent to a new Version once every case in its Tenant passes on that Version. [Verb page](/business/nouns/agent/upgrade?interface=api).

```text
POST /{namespace}/agents/{agent}/upgrade
```

Path: `agent`. Body, as JSON: the other inputs. Emits [`Agent.upgraded`](/business/events/Agent.upgraded).

**Inputs**

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `agent` | [Agent](/business/nouns/agent) | Yes | The minted Agent. |
| `version` | [Version](/business/nouns/version) | Yes | The target Version. |

**Returns**

| Output | Type | Required | Description |
| --- | --- | --- | --- |
| `agent` | [Agent](/business/nouns/agent) | Yes | The Agent, on the target Version. |

**Refuses when**

| Check | Error | Fix | Then call |
| --- | --- | --- | --- |
| The key is valid, but its scopes do not allow this operation | [`forbidden`](/code/api/errors/forbidden) | Use a key whose scopes cover the operation, or ask an owner of the namespace to grant them. | None. |
| `agent` is missing, or is not a agent | [`invalid-input`](/code/api/errors/invalid-input) | Send `agent` as a agent, then call it again. | None. |
| `version` is missing, or is not a version | [`invalid-input`](/code/api/errors/invalid-input) | Send `version` as a version, then call it again. | None. |
| The `Idempotency-Key` was sent before with another operation or other input | [`idempotency-mismatch`](/code/api/errors/idempotency-mismatch) | Send a new key for new input; reuse a key only to retry the same request. | None. |

**Example**

```bash
curl -X POST https://api.sb/leaseline.app/agents/agent_tCzKDMorKn/upgrade \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Idempotency-Key: leaseline-agent-upgrade-1" \
  -H "Content-Type: application/json" \
  -d '{"version":"version_4HTEMs14G4"}'
```

```json
{
  "api": "https://api.sb/leaseline.app",
  "agent": {
    "$id": "https://api.sb/leaseline.app/agents/agent_tCzKDMorKn",
    "$type": "Agent",
    "instructions": "Write as the property manager’s assistant. Never promise a rent the manager has not set.",
    "model": "claude-opus-5-5",
    "status": "seated"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/act_br07HsG8MG",
    "operation": "Agent.upgrade",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/act_br07HsG8MG"
  }
}
```