Metadata-Version: 2.4
Name: burnledger
Version: 0.3.0
Summary: Python SDK for the BurnLedger API
License-Expression: MIT
Project-URL: Homepage, https://burnledger.io/docs/
Project-URL: Documentation, https://burnledger.io/docs/
Project-URL: Verifier, https://burnledger.io/verify/
Project-URL: Support, https://burnledger.io/contact/
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.25.0
Requires-Dist: cryptography>=41.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
Requires-Dist: respx>=0.21; extra == "dev"
Requires-Dist: mypy==2.3.1; extra == "dev"
Dynamic: license-file

# BurnLedger Python SDK

Python client for the [BurnLedger](https://burnledger.io) API — cryptographic deletion certificates for regulatory compliance.

## Install

```bash
pip install burnledger
```

**Requirements:** Python 3.10+

## Quick Start

```python
from burnledger import BurnLedger

with BurnLedger(api_key="dp_...") as dp:
    # 1. Attest — snapshot systems before deletion
    att = dp.attest("user@example.com", system_ids=["sys_abc", "sys_def"])

    # 2. Delete data (your code, your tools)

    # 3. Verify — confirm deletion and get certificate
    result = dp.verify(att.id, "user@example.com", timeout=60)

    # 4. Download certificate PDF
    dp.save_pdf(result.certificate.id, "./deletion-cert.pdf")
```

### Async

```python
from burnledger import AsyncBurnLedger

async with AsyncBurnLedger(api_key="dp_...") as dp:
    att = await dp.attest("user@example.com", system_ids=["sys_abc"])
    result = await dp.verify(att.id, "user@example.com", timeout=60)
```

## Offline Verification

Verify certificates without network access using Ed25519 signatures:

```python
from burnledger import verify_certificate, verify_transparency, PublicKeyInfo

key = PublicKeyInfo.from_hex("abcdef...", revoked=False)
keys = {key.key_id: key}

cert_result = verify_certificate(certificate, keys)
# VerificationResult.VALID or raises VerificationError

log_result = verify_transparency(certificate, keys)
# TransparencyResult.INCLUDED or raises VerificationError
```

## Webhook Verification

Verify incoming webhook signatures (HMAC-SHA256):

```python
from burnledger import verify_webhook_signature

valid = verify_webhook_signature(
    secret=webhook_secret,         # from dp.register_webhook()
    body=request.body,             # raw request body
    signature=request.headers["X-BurnLedger-Signature"],
)
```

## API Reference

### Client

```python
BurnLedger(
    api_key: str,
    *,
    base_url: str = "https://api.burnledger.io",
    timeout: float = 30.0,
    max_retries: int = 2,
)
```

### Systems

| Method | Returns |
|--------|---------|
| `register_system(**opts)` | `System` |
| `get_system(id)` | `System` |
| `list_systems(limit=25)` | `SyncPaginator[System]` |
| `deregister_system(id)` | `None` |
| `health_check(id)` | `System` |

### Attestations

| Method | Returns |
|--------|---------|
| `attest(subject, **opts)` | `Attestation` |
| `batch_attest(subjects, **opts)` | `BatchAttestationResponse` |
| `get_attestation(id)` | `Attestation` |
| `wait_for(id, **opts)` | `Attestation` |
| `verify(id, subject, **opts)` | `VerifyResult` |

### Certificates

| Method | Returns |
|--------|---------|
| `get_certificate(id)` | `CertificateResponse` |
| `list_certificates(limit=25)` | `SyncPaginator[CertificateResponse]` |
| `get_certificate_stats()` | `CertificateStats` |
| `export_certificates(**opts)` | `bytes` |
| `download_pdf(id)` | `bytes` |
| `save_pdf(id, path)` | `None` |
| `get_revocation_status(id)` | `RevocationStatus` |
| `revoke_certificate(id, reason=...)` | `CertificateResponse` |

### Webhooks

| Method | Returns |
|--------|---------|
| `register_webhook(url=...)` | `Webhook` |
| `list_webhooks(limit=25)` | `SyncPaginator[Webhook]` |
| `delete_webhook(id)` | `None` |
| `rotate_webhook_secret(id)` | `WebhookRotateResponse` |
| `commit_webhook_rotation(id)` | `None` |
| `list_failed_deliveries(id)` | `list[WebhookDelivery]` |
| `retry_delivery(webhook_id, delivery_id)` | `None` |
| `resolve_delivery(webhook_id, delivery_id)` | `None` |

### API Keys

| Method | Returns |
|--------|---------|
| `list_api_keys()` | `list[ApiKeyListItem]` |
| `create_api_key()` | `ApiKeyResponse` |
| `revoke_api_key(id)` | `None` |

### Transparency Log

These methods do not require authentication.

| Method | Returns |
|--------|---------|
| `get_log_head()` | `SignedTreeHead` |
| `get_log_entry(index)` | `LogEntry` |
| `get_log_entries(start, end)` | `list[LogEntry]` |
| `get_inclusion_proof(index, tree_size)` | `InclusionProof` |
| `get_consistency_proof(old_size, new_size)` | `ConsistencyProof` |

### Pagination

All `list_*` methods return a paginator that auto-fetches pages:

```python
for cert in dp.list_certificates():
    print(cert.id)

# async
async for cert in dp.list_certificates():
    print(cert.id)
```

## License

MIT
