# Python SDK

Use the Python SDK when you want the fastest path to integrating ZeroID into a developer tool, backend service, or agent runtime.

The Python client wraps both admin workflows and public token workflows in a single `ZeroIDClient`.

### Choosing the Right Method

| I want to...                                               | Use                                                                       |
| ---------------------------------------------------------- | ------------------------------------------------------------------------- |
| Register a new agent                                       | `client.agents.register()`                                                |
| Get an access token from an API key                        | `client.tokens.issue(grant_type="api_key", ...)`                          |
| Verify a token fast (no network, no revocation check)      | `client.tokens.verify()`                                                  |
| Verify a token and check for revocation                    | `client.tokens.session()`                                                 |
| Verify from a raw `Authorization: Bearer ...` header       | `client.tokens.verify_bearer()` or `client.tokens.session_from_request()` |
| Delegate authority to a sub-agent                          | `client.tokens.delegate()`                                                |
| Check if a token is still active (online)                  | `client.tokens.introspect()`                                              |
| Invalidate a token                                         | `client.tokens.revoke()`                                                  |
| Ingest a CAE signal (e.g. session revoked)                 | `client.signals.ingest()`                                                 |
| Control what grant types and delegation depths are allowed | `client.credential_policies.create()`                                     |

### verify() vs session()

|                                       | `tokens.verify()`                       | `tokens.session()`                             |
| ------------------------------------- | --------------------------------------- | ---------------------------------------------- |
| Network call                          | No — uses cached JWKS                   | Yes — calls introspection endpoint             |
| Reflects revocation                   | Not until JWKS rotates                  | Immediately                                    |
| Latency                               | \~1ms (local)                           | \~20–50ms (network)                            |
| Returns                               | `ZeroIDIdentity`                        | `AgentSession`                                 |
| `require_scope()` / `require_trust()` | No                                      | Yes                                            |
| Use when                              | Service mesh, hot path, high throughput | User-facing endpoints, high-security decisions |

> **When in doubt:** use `verify()` inside your service mesh where revocation lag is acceptable, and `session()` at your public API boundary where you need real-time revocation awareness.

### Installation

```bash
pip install highflame
```

For delegation examples that build signed assertions locally:

```bash
pip install cryptography PyJWT
```

### Create a Client

```python
from highflame.zeroid import ZeroIDClient

client = ZeroIDClient(
    base_url="http://localhost:8899",
    account_id="acct-demo",
    project_id="proj-demo",
)
```

For local development, you can omit `account_id` and `project_id` and let the client generate them.

### Available Resources

Current Python resources:

* `client.identities`
* `client.agents`
* `client.oauth_clients`
* `client.credential_policies`
* `client.api_keys`
* `client.tokens`
* `client.signals`

Convenience methods:

* `client.health()`
* `client.jwks()`

### Register an Agent

```python
registered = client.agents.register(
    name="Data Fetcher",
    external_id="data-fetcher",
    sub_type="tool_agent",
    trust_level="first_party",
    created_by="dev@company.com",
)

print(registered.identity.id)
print(registered.identity.wimse_uri)
print(registered.api_key)
```

Use `client.identities` instead when you want lower-level identity control instead of the higher-level agent registration convenience API.

### Issue a Token

```python
token = client.tokens.issue(
    grant_type="api_key",
    api_key=registered.api_key,
)

print(token.access_token)
print(token.expires_in)
```

### Introspect and Revoke

```python
info = client.tokens.introspect(token.access_token)
print(info.active)

client.tokens.revoke(token.access_token)
```

### Delegate to a Sub-Agent

If the client was initialized with an API key, the Python SDK can automatically use the cached access token as the `subject_token`:

```python
delegated = client.tokens.delegate(
    actor_token=actor_token,
    scope="data:read",
)
```

This is the cleanest way to implement orchestrator to sub-agent delegation from Python.

### Verify a Token Locally

Use `tokens.verify()` or `tokens.verify_bearer()` to validate a JWT using ZeroID's JWKS without a network round-trip to the introspection endpoint.

{% hint style="info" %}
**Use `verify()` when** you need low latency and can tolerate a brief window where a revoked token still passes (until the next JWKS rotation). Ideal for service-to-service calls inside a trust boundary.
{% endhint %}

```python
# From a raw token string
identity = client.tokens.verify(token.access_token)

# From an Authorization header value
identity = client.tokens.verify_bearer(request.headers["Authorization"])

print(identity.sub)
print(identity.trust_level)
```

The returned `ZeroIDIdentity` object includes helper methods:

```python
identity.has_scope("data:read")   # bool
identity.has_tool("bash")         # bool
identity.is_delegated()           # bool — True if act.sub is present
identity.delegated_by()           # str | None — the orchestrator sub
```

Async variants: `averify()`, `averify_bearer()`.

### Session Verification (Introspection-Based)

Use `tokens.session()` or `tokens.session_from_request()` for an online check that reflects the latest revocation state.

{% hint style="info" %}
**Use `session()` when** you need immediate revocation awareness — e.g. at a public API boundary or before a high-risk action. It makes a network call to the introspection endpoint. `require_scope()` and `require_trust()` (which raise on failure) are only available on `AgentSession`, not on `ZeroIDIdentity`.
{% endhint %}

```python
# From a raw token string
session = client.tokens.session(token.access_token)

# From request headers (reads the Authorization: Bearer ... header)
session = client.tokens.session_from_request(request.headers)

if not session.active:
    # token revoked or expired
    pass

session.has_scope("data:read")         # bool
session.require_scope("data:read")     # raises if scope missing
session.is_delegated()                 # bool
session.delegated_by()                 # str | None
session.require_trust("first_party")   # raises if trust level below minimum
```

Async variants: `asession()`, `asession_from_request()`.

### Manage Policies

```python
policy = client.credential_policies.create(
    name="tool-agent-policy",
    max_ttl_seconds=600,
    allowed_grant_types=["token_exchange"],
    allowed_scopes=["data:read"],
    required_trust_level="first_party",
    max_delegation_depth=0,
)
```

### Manage Signals

```python
signal = client.signals.ingest(
    signal_type="session_revoked",
    severity="critical",
    source="runtime-monitor",
    identity_id=registered.identity.id,
    payload={"reason": "suspicious tool use"},
)
```

### Recommended Usage Pattern

For most Python services:

1. create one `ZeroIDClient` per process
2. set explicit tenant IDs in non-local environments
3. use `client.agents.register()` for first registration flows
4. use `client.tokens.issue()` for direct auth
5. use `client.tokens.delegate()` for delegation

### When To Drop Down To REST

Today, use REST directly if you need a server feature that has not yet been surfaced through Python resources, such as a newly added admin endpoint.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.highflame.ai/api-reference/sdk/zeroid/python-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
