Metadata-Version: 2.1
Name: umbra-sdk
Version: 0.3.0
Summary: Umbra client: pay per request with x402, get a signed receipt. Chat, streaming, tool calling, spend caps.
Home-page: https://umbra-inference.app
License: MIT
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: requests (>=2.28)
Requires-Dist: eth-account (>=0.10)
Requires-Dist: eth-utils (>=2.0)
Requires-Dist: cryptography (>=41)

# umbra-sdk

Pay per request with x402, get the answer and a signed receipt. Chat (OpenAI route), messages (Anthropic route), streaming, tool calling, quotes, receipt verification, wallet status and client-side spend caps. Python 3.9+.

```bash
pip install https://umbra-inference.app/releases/umbra_sdk-0.3.0-py3-none-any.whl
```

```python
from umbra_sdk import Umbra

u = Umbra(private_key=os.environ["EVM_PRIVATE_KEY"], caps={"per_call": 0.05, "per_hour": 1.0})

r = u.chat(model="deepseek/deepseek-v4-flash-0731", messages=[{"role": "user", "content": "hi"}], max_tokens=300)
print(r.text, r.receipt_valid, r.receipt["receipt"]["cost"]["settled"], r.settlement["transaction"])

s = u.stream(model="claude-haiku-5-5", messages=[...], max_tokens=300, tools=tools)
for ev in s:
    if ev["type"] == "text": print(ev["text"], end="")
print(s.result.tool_calls, s.result.receipt)
```

Payment: x402 `exact` (EIP-3009 `transferWithAuthorization`), offered on every network, no on-chain setup. Streams and long answers use the gateway's upfront flow with the same signature and an on-chain refund of the unused ceiling. `upto` and paying in UMBRA (Permit2) are in the TypeScript SDK and the CLI, not here yet.

Options: `base_url`, `network` (`eip155:4663` USDG default, `eip155:8453` / `eip155:84532` USDC), `caps` (USD, checked against the quoted ceiling before signing; `SpendCapError` otherwise), `ledger_path` (`~/.umbra-spend.json`, `None` for in-memory), `task`, `holder_hint`.

Methods: `chat`, `messages`, `stream`, `quote`, `models`, `well_known`, `verify_receipt`, `wallet`, `spend`.

`verify_receipt(signed)` is parse, verify, anchor, settle in one call: shape against the bundled JSON Schema (`validate_receipt_shape` for the shape alone), Ed25519 signature over the canonical receipt, and the key anchored in https://umbra-inference.app/keys.json with `issued_at` inside its window. `valid` needs all three; `key_matches_gateway` tells a retired key from the live one.

Since 0.3.0 the same call also reads the chain for upfront receipts (streams, long answers, gateway 0.16.0+): `cost.settlement_tx` is fetched from the network's public RPC and the transfer to the gateway must equal the ceiling (`authorized_atomic`); `cost.refund_tx` must return `refunded_atomic` to the payer; settlement minus refund must equal `settled_atomic`. The result is in `["chain"]` (`ok`, `settlement`, `refund`, `net_paid`, `net_ok`, `settled_before_signing_ms`), and `valid` requires it when a settlement transaction is present and the RPC answered. After-answer receipts have no settlement transaction (`chain` is None). `verify_receipt(signed, chain=False)` skips the RPC; `rpc={"eip155:4663": url}` overrides it.


