Metadata-Version: 2.4
Name: licensefoundry
Version: 0.3.0
Summary: Python SDK for licensefoundry — issuance, verification, and CoMP-shaped translation of W3C Verifiable Credentials.
Project-URL: Homepage, https://licensefoundry.com
Project-URL: Repository, https://github.com/ReadBridge/licencefoundry
Project-URL: Issues, https://github.com/ReadBridge/licencefoundry/issues
Author: licensefoundry
License: Apache-2.0
Keywords: ai-licensing,comp,did,jwt-vc,verifiable-credentials
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: cryptography>=42.0.0
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# `licensefoundry`

Python SDK for licensefoundry — issuance, verification, and CoMP-shaped translation of W3C Verifiable Credentials (JWT-VC encoded, Ed25519-signed).

**Built in:** Phase 5 of [`/docs/path-c-rebuild-plan.md`](../../docs/path-c-rebuild-plan.md).

## Install

```bash
pip install licensefoundry
```

Requires Python ≥ 3.10.

## Quick start

```python
import os
from licensefoundry import (
    LicenseFoundryClient,
    IssueCredentialRequest,
    Rights,
    TrainGrant,
    TrainScope,
    CommercialGrant,
    CredentialScope,
    Attribution,
    CapabilityNotEnabledError,
)

with LicenseFoundryClient(
    base_url="https://api.licensefoundry.com",
    api_key=os.environ["LICENSEFOUNDRY_API_KEY"],
    # Production verifiers MUST list only their production issuer DID
    accepted_issuers=["did:web:licensefoundry.com"],
) as lf:
    try:
        cred = lf.issuer.issue_credential(IssueCredentialRequest(
            asset_id="...",
            rights=Rights(
                train=TrainGrant(granted=True, scope=TrainScope(model_family="open-source")),
                commercial=CommercialGrant(granted=True),
            ),
            scope=CredentialScope(
                audience="single_product",
                product_id="my-rag",
                jurisdiction=["US"],
                attribution=Attribution(required=True),
            ),
        ))
        print(cred.credential_jwt)
    except CapabilityNotEnabledError as e:
        show_upgrade_modal(plan=e.required_plan, url=e.upgrade_url)

    # Verify offline (uses cached JWKS + Status List 2021)
    result = lf.verifier.verify(some_jwt)
    if not result.valid:
        print("invalid:", result.errors)
```

## Public surface

| Module                    | Use for                                                            |
| ------------------------- | ------------------------------------------------------------------ |
| `lf.issuer`               | `register_asset`, `issue_credential`, `revoke_credential`, status  |
| `lf.verifier`             | Offline verification with cached JWKS and Status List 2021         |
| `licensefoundry.comp`     | `from_credential(vc)`, `satisfies(vc, function=, ause=, ...)`      |

The customer-facing API uses canonical Path C field names (`train`, `rag`, `embed`, `display`, `eval`, `derive`, `commercial`). CoMP terminology (`function`, `subfn`, `ause`, `licensedur`, etc.) is opt-in via `licensefoundry.comp`.

## Typed errors

Per [`/docs/auth-access-flows.md`](../../docs/auth-access-flows.md) §4.5, HTTP failures surface as typed exceptions:

| Exception                    | When                                                      |
| ---------------------------- | --------------------------------------------------------- |
| `AuthError`                  | 401 — bad/missing API key                                 |
| `CapabilityNotEnabledError`  | 402 with `error: capability_not_enabled` — upgrade needed |
| `ScopeDeniedError`           | 403 — API key scope rejects this action                   |
| `NotFoundError`              | 404                                                       |
| `ConflictError`              | 409 — e.g. asset not yet anchored                         |
| `ValidationError`            | 422                                                       |
| `RateLimitedError`           | 429 — carries `retry_after`                               |
| `ServerError`                | 5xx                                                       |
| `NetworkError`               | request failure / timeout                                 |
| `VerificationError`          | raised by `verifier.verify_or_raise()`                    |

## Verification

`Verifier` performs offline verification per [`/docs/credential-format.md`](../../docs/credential-format.md) §7:

1. Parse JWT
2. Resolve issuer (cached `did:web` → JWKS)
3. EdDSA signature verification (via `cryptography`)
4. Temporal validity
5. `@context` and issuer accepted-list checks
6. Revocation via Status List 2021 bitstring (cached)

Per [`/docs/billing-model.md`](../../docs/billing-model.md) §2, **offline verification is free** — no metering event. Online verification (calling the issuer's `/v1/credentials/verify` endpoint) is metered.

## Specs that govern this SDK

- [`/docs/credential-format.md`](../../docs/credential-format.md) — wire format and verification
- [`/docs/comp-mapping.md`](../../docs/comp-mapping.md) — CoMP translation
- [`/docs/auth-access-flows.md`](../../docs/auth-access-flows.md) §4.5 — typed error contracts
- [`/docs/billing-model.md`](../../docs/billing-model.md) §2 — what is metered

## Develop

```bash
pip install -e ".[dev]"
pytest
ruff check .
mypy src
```
