Metadata-Version: 2.4
Name: ppx-client
Version: 0.1.0a1
Summary: Python client for the Preference Profile Exchange (PPX) reference provider and any conformant implementation.
Project-URL: Homepage, https://blazing-customs.github.io/ppx-spec/
Project-URL: Documentation, https://github.com/Blazing-Customs/ppx-sdks/tree/main/python/ppx-client#readme
Project-URL: Source, https://github.com/Blazing-Customs/ppx-sdks/tree/main/python/ppx-client
Project-URL: Repository, https://github.com/Blazing-Customs/ppx-sdks
Project-URL: Issues, https://github.com/Blazing-Customs/ppx-sdks/issues
Project-URL: Changelog, https://github.com/Blazing-Customs/ppx-sdks/blob/main/CHANGELOG.md
Author: Blazing Customs
License: Apache-2.0
License-File: LICENSE
Keywords: a2a,ag-ui,agents,ai,consent,mcp,oauth,ppx,preference-profile-exchange
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Requires-Dist: httpx-sse>=0.4.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.9.0
Provides-Extra: cli
Provides-Extra: dev
Requires-Dist: mypy>=1.11.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.6.0; extra == 'dev'
Description-Content-Type: text/markdown

# ppx-client

> Python client for the [Preference Profile Exchange (PPX)](https://blazing-customs.github.io/ppx-spec/)
> reference provider and any conformant implementation.

## Install

```bash
pip install ppx-client
```

Requires Python 3.11+. Published version: **0.1.0a1** ([PyPI](https://pypi.org/project/ppx-client/)).

> Alpha, tracking a **draft** specification. Expect breaking changes.
> The version is `0.1.0a1` on PyPI and `0.1.0-alpha.1` on npm — the
> same release in each ecosystem's required format.

## Quick start (sync)

```python
from ppx_client import PpxClient, GrantRequestInput, consent_redirect_url

with PpxClient(base_url="https://api.provider.app") as ppx:
    req = ppx.request_grant(GrantRequestInput(
        client_id="my-app",
        subject_id="did:example:user-123",
        purposes=["recommendation"],
        allowed_domains=["fragrance"],
        allowed_namespaces=["fragrance"],
        allowed_operations=["read"],
        cross_domain_transfer="deny",
        writeback_policy="review_required",
        requested_duration_days=30,
    ))

    # Send the user here to review and approve
    consent_url = consent_redirect_url(
        "https://app.provider.app",
        req.grant_request_id,
        return_to="https://my-app.example/callback",
    )

    # After approval, exchange for a grant-scoped token
    tok = ppx.mint_token(req.grant_request_id)

    # Use it to read scoped claims
    profile = ppx.effective_profile(
        context={"climate": "hot_humid"},
        requested_namespaces=["fragrance"],
        token=tok.access_token,
    )
```

## Async

```python
import asyncio
from ppx_client import PpxAsyncClient, GrantRequestInput

async def main():
    async with PpxAsyncClient(base_url="https://api.provider.app") as ppx:
        card = await ppx.discovery_card()
        print(card.name, card.supported_namespaces)

asyncio.run(main())
```

## Grant re-use

```python
from ppx_client import PpxGrantRevokedError

try:
    fresh = ppx.refresh("my-app", cached_grant_id)
except PpxGrantRevokedError:
    # Clear cache, re-run the full approval flow
    cached_grant_id = None
```

## AG-UI consent event streaming

```python
from ppx_client import subscribe_ag_ui

for event in subscribe_ag_ui(f"https://api.provider.app/v1/ag-ui/consent/{req_id}"):
    print(event["type"], event)
    if event["type"] == "RUN_FINISHED":
        break
```

Async variant: `subscribe_ag_ui_async`.

## License

Apache-2.0.
