# client.providers

> client.providers — the providers operations.

`client.providers` — the `providers` operations.

On `AsyncKindgi` every method is the same, awaited.

## `client.providers.list()`

```python signature
list(
    *,
    limit: int | None = None,
    cursor: str | None = None,
    feature: str | None = None,
    timeout: float | None = None,
) -> ProviderCollectionPage
```

List model providers. `GET /v1/providers`

Cursor-paginated. Optional `?feature=` filters to providers whose `metadata.features` includes the given feature (exact match).

## `client.providers.register()`

```python signature
register(
    body: RegisterProviderBody | Mapping[str, Any] | None = None,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
    **fields: Any,
) -> RegisterProviderResult
```

Register a model provider. `POST /v1/providers`

Body is a full `ProviderMetadata`. Server validates shape: provider-level `id` + `region` non-empty; `models[]` non-empty with unique `name` per entry; per-model `contextWindow` positive integer; per-model `features` against the closed enum; per-model `cost` non-negative; optional per-model `p95LatencyMs` / `maxOutputTokens` well-shaped; optional `labels` within their limits — same rules as `@kindgi/capabilities.createProviderRegistry`. Secrets (API keys, endpoints) are NOT part of the wire shape; deployments store them inside the binding. When the runtime has the adapter the body names, that adapter checks the registration first (its `adapter_config`, the metadata and the presence of `secret_ref`; static: no network, no secret read): a problem refuses it with `422 provider-config-invalid`. A model provider's key is used by its provider only: a `secret_ref` naming a secret that a tool, an MCP endpoint or a webhook endpoint already uses is refused (`409 provider-key-in-use`), and from then on the name is refused to tools and endpoints.

## `client.providers.get()`

```python signature
get(provider_id: str | UUID, /, *, timeout: float | None = None) -> ProviderMetadata
```

Fetch a provider. `GET /v1/providers/{providerId}`

Returns the wire-safe `ProviderMetadata` (routing metadata only — secrets never cross the wire).

## `client.providers.capabilities()`

```python signature
capabilities(
    provider_id: str | UUID,
    /,
    *,
    timeout: float | None = None,
) -> ProviderCapabilitiesResult
```

List capabilities a provider satisfies. `GET /v1/providers/{providerId}/capabilities`

Sub-resource: returns the catalog capability descriptors the provider fulfils. Empty array = known provider with no matches; 404 = unknown provider.

## `client.providers.check()`

```python signature
check(
    provider_id: str | UUID,
    /,
    *,
    timeout: float | None = None,
) -> ProviderCheckResult
```

Check a provider's registration. `GET /v1/providers/{providerId}/check`

Runs the provider's adapter check over its stored registration (its `adapter_config`, its metadata, whether it names a `secret_ref`): the check `POST /v1/providers` runs before it stores one. Static: no network call, no secret read. `issues` lists what would keep the runtime from building the provider, each with a JSON-pointer `path`; an adapter this runtime doesn't have is one (`/adapter_id`). `checked` is false when this runtime has no check for the provider's adapter.

## `client.providers.unregister()`

```python signature
unregister(
    provider_id: str | UUID,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
) -> UnregisterProviderResult
```

Unregister a model provider. `POST /v1/providers/{providerId}/unregister`

A tombstone, not an erase: from then on the provider is gone from list, get and capabilities, and the router never picks it. Its id is free to register again. A retention policy on the `provider` domain purges the row.
