Metadata-Version: 2.4
Name: blockchain0x
Version: 0.0.1a0
Summary: Official Python SDK for the Blockchain0x non-custodial AI-agent wallet platform
Project-URL: Homepage, https://blockchain0x.com
Project-URL: Documentation, https://docs.blockchain0x.com
Project-URL: Repository, https://github.com/Tosh-Labs/blockchain0x-python
Project-URL: Source, https://github.com/Tosh-Labs/blockchain0x-app/tree/dev/packages/sdk-python
Project-URL: Changelog, https://github.com/Tosh-Labs/blockchain0x-python/blob/main/CHANGELOG.md
Project-URL: Issue Tracker, https://github.com/Tosh-Labs/blockchain0x-app/issues
Author-email: Blockchain0x <support@blockchain0x.com>
License: Apache-2.0
License-File: LICENSE
Keywords: agent,blockchain0x,stablecoin,usdc,wallet,x402
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Description-Content-Type: text/markdown

# blockchain0x (Python SDK)

**Official Python SDK for [Blockchain0x](https://blockchain0x.com)** -
the non-custodial AI-agent wallet platform on Base.

> Pre-release: `0.0.1a0` ships the operational essentials - HTTP
> transport, `apiKeys` resource, and `webhooks.verify`. The full
> surface (every resource + x402 client + async client) lands in the
> 21.3 Phase C follow-up rows.

## Install

```bash
pip install blockchain0x
```

Requires Python 3.9 or newer.

## Quick start

```python
from blockchain0x import Client

client = Client(api_key="sk_test_...")
for key in client.api_keys.list()["data"]:
    print(key["id"], key["prefix"])
```

The client pins the network from the api-key prefix
(`sk_test_*` → testnet, `sk_live_*` → mainnet). Override with
`Client(api_key=..., network="mainnet")` when you need both modes in
one process (mixed-mode tests).

## Verify webhook signatures

This is the single most important utility this SDK ships - drop it
into the top of your webhook handler BEFORE touching the body.

```python
from blockchain0x import webhooks

# In your Flask / FastAPI / Django handler:
def receive_webhook(req, raw_body, secret):
    result = webhooks.verify(headers=req.headers, raw_body=raw_body, secret=secret)
    if not result.ok:
        return {"code": result.code}, 400
    # result.event_type / result.event_id / result.delivery_id populated
    process_event(raw_body, result.event_type)
```

The verifier:

- Reads `X-Blockchain0x-Signature` in either `t=<ts>,v1=<hex>` or
  bare-hex form (some load balancers strip commas).
- Falls back to `X-Blockchain0x-Timestamp` when the signature is bare.
- Rejects with `webhook.timestamp_outside_window` when drift exceeds
  300s (5-minute replay window; matches the worker).
- Constant-time compares via `hmac.compare_digest`.

For exception-based flows pass `raise_on_fail=True`:

```python
try:
    webhooks.verify(headers=req.headers, raw_body=raw_body, secret=secret, raise_on_fail=True)
except WebhookSignatureError as e:
    return {"code": e.code}, 400
```

## Errors

Two classes:

- `Blockchain0xError` - base class; every SDK error inherits.
- `ApiKeyError` - subclass for HTTP 401 / 403 envelopes whose
  `error.code` starts with `apikey.` (e.g. `apikey.scope_insufficient`,
  `apikey.wallet_not_assigned`).

Always branch on `.code`, never regex-match `.message`:

```python
from blockchain0x import ApiKeyError

try:
    client.api_keys.list()
except ApiKeyError as e:
    if e.code == "apikey.scope_insufficient":
        # mint a fresh key with more scope
        ...
```

## Workspace keys (sub-plan 21.3)

Two key shapes exist (see [docs/concept-api-key-types.md](https://github.com/Tosh-Labs/blockchain0x-app/blob/dev/docs/concept-api-key-types.md) for the full decision tree):

- **Wallet-only**: bound to ONE agent via `agent_id`. The right shape for an autonomous AI agent that IS one wallet.
- **Workspace**: for human operators that can carry workspace-level scopes AND assignments to N specific wallets.

The Python SDK forwards both shapes through the same `client.api_keys` resource; the body shape decides the flavor on the server. Once the create surface lands beyond the C-2 scaffold:

```python
key = client.api_keys.create(
    label="Treasury daily reconciliation",
    workspace_scopes=["read_workspace"],
    wallet_assignments=[
        {"agentId": "agt_trading", "scopes": ["read_wallet_metadata"]},
        {"agentId": "agt_settlement", "scopes": ["read_wallet_metadata"]},
    ],
    expires_in_days=30,
)
print(key["secret"])  # shown ONCE
```

Server-side RBAC: the minter cannot grant a scope they do not have themselves. Over-grants reject with `apikey.role_insufficient_for_grants` - catch `ApiKeyError` and branch on `e.code`.

Cascade behaviour: when an assigned wallet is soft-deleted, the assignment row is removed. If the key has zero workspace scopes AND no remaining assignments, it auto-revokes with `apikey.no_grants_remaining`. Mint a fresh key.

## x402 (Phase C-7)

The sibling package `blockchain0x-x402` (Python port of [`@blockchain0x/x402`](https://www.npmjs.com/package/@blockchain0x/x402)) will ship the x402 client + FastAPI / Starlette / Flask adapters in sub-plan 21.3 row C-7. The wire format is identical across languages so a Python service can accept payments from a Node client and vice-versa.

## Retry behaviour

The transport retries on `429` and `5xx` with exponential backoff
(0.5s → 1s → 2s → ... → 30s cap). `Retry-After` is honoured when the
server sends it. Network errors (timeout, connection drop) get the
same retry budget.

`POST` / `PATCH` / `DELETE` requests carry an `Idempotency-Key` header

- the SDK mints a uuid4 if you do not supply one. Pass
  `idempotency_key="..."` to thread a stable key across SDK retries OR
  across processes (e.g. cron jobs that hash their input deterministically).

## Codegen

Type-only DTOs are generated from `apps/backend/openapi/openapi.yaml`
via [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator).
Transport, retry, error mapping, and the webhook verifier stay
handwritten - see [codegen/README.md](./codegen/README.md) for the
decision rationale.

## Source-of-truth + distribution

Source-of-truth: this directory in
[Tosh-Labs/blockchain0x-app](https://github.com/Tosh-Labs/blockchain0x-app)
under `packages/sdk-python/`.

Public mirror: [Tosh-Labs/blockchain0x-python](https://github.com/Tosh-Labs/blockchain0x-python)
(receives merges from this directory on each push to `dev`).

Distribution: [pypi](https://pypi.org/project/blockchain0x/) via
Trusted Publisher OIDC.

## License

Apache-2.0.
