Metadata-Version: 2.4
Name: agents-u-cash
Version: 0.5.0
Summary: Zero-dependency Python client for the agents.u.cash 402 Online Protocol API - non-custodial agent payments (buy + sell).
Author: U.CASH
License: MIT
Project-URL: Homepage, https://agents.u.cash
Project-URL: Repository, https://github.com/UdotCASH/agents-u-cash
Project-URL: Bug Tracker, https://github.com/UdotCASH/agents-u-cash/issues
Keywords: agents.u.cash,x402,402,payments,crypto,non-custodial,ai-agents
Requires-Python: >=3.7
Description-Content-Type: text/markdown

# agents-u-cash (Python)

Zero-dependency Python client for the [agents.u.cash](https://agents.u.cash) API - the 402 Online Protocol for non-custodial agent payments. Works for **both sides** of the network: an agent selling (manage resources, watch settlements) and a buyer (fetch a 402 door, pay, and settle - automatically via on-chain detection, or instantly by submitting the tx hash). Supports ~40 native coins (Bitcoin + Lightning, Ethereum + 15 EVM L2s, Solana, Tron, XRP, USDT/USDC, **USDC-on-Base** gasless, **UCASH**) plus custom tokens on 20 chains (ERC-20 / TRC-20 / SPL / ...) - see [agents.u.cash](https://agents.u.cash) for the full live list.

Uses only the standard library (`urllib`). No dependencies. Python 3.7+.

## Install

```bash
pip install agents-u-cash
```

Or copy `agents_u_cash.py` - it has no dependencies.

## Sell (as an agent)

```python
from agents_u_cash import AgentsUCash

# Get an API key once (wallet-first; works at $0 immediately - verify email optionally for free credit):
# key = AgentsUCash().signup(email="me@agent.dev", password="longpass")["api_key"]

agent = AgentsUCash(api_key="...")
agent.set_wallet("btc", "bc1q…")
agent.set_webhook("https://my.bot/webhook")

res = agent.create_resource(amount=0.05)               # priced resource
acc = agent.create_challenge(res["res_id"])             # what a buyer pays
# Share the payable link: https://agents.u.cash/r/{res_id}

settled = agent.get_settlements()                       # your earnings log
```

## Buy (as a buyer)

```python
from agents_u_cash import AgentsUCash

buyer = AgentsUCash()                                   # no key needed to buy
door = buyer.view_door(res_id)                          # the 402 door (JSON)
# 1. pick an entry, pay entry["payTo"] exactly entry["amount"] from your wallet (out of band)
# 2. the platform auto-detects the on-chain payment and settles it.
#    Optionally POST the tx hash to settle instantly instead:
result = buyer.verify(door["accepts"][0]["challengeId"], tx_hash)
# -> {"settled": True} | {"status": "pending", "confirmations": n, "required": m}
```

A human-friendly payable page is also available: `buyer.view_door(res_id, html=True)` returns the HTML.

## UCP checkout sessions (buyer)

Multi-item, mixed-currency carts over the [Universal Commerce Protocol](https://ucp.dev). The merchant is resolved from the custom-domain `base_url`, or from a `cloud` merchant token on the shared host. No API key.

```python
buyer = AgentsUCash()   # base_url = the merchant's domain (or the platform host + cloud)
cart = buyer.create_checkout(
    line_items=[{"item": {"id": res_id_a}, "quantity": 1}, {"item": {"id": res_id_b}, "quantity": 2}],
    currency="USD",            # optional: cart currency for mixed-currency carts
    cloud="<merchant-token>",  # only on the shared platform host
)
# -> {"id": ..., "status": "incomplete", "currency", "line_items", "totals", "ap2": {"merchant_authorization", "nonce"}}
ready = buyer.complete_checkout(cart["id"], cloud="<merchant-token>")
# -> ready_for_complete + payment_handlers[] (pay each challenge on-chain)
order = buyer.get_order(cart["id"], cloud="<merchant-token>")   # per-item fulfillment status
```

Optional AP2 (`dev.ucp.shopping.ap2_mandate`): pass `complete_checkout(id, ap2={"checkout_mandate": ...}, cloud=...)` with a buyer-signed SD-JWT-VC for holder-proof authorization. Responses are RFC 9421-signed (ES256) with the merchant key.

## Manage your store (full merchant surface)

Beyond priced 402 resources, an agent is a first-class merchant over its own account: full transaction history + actions, multi-store, shop products, landers, payout-info/OTC, discount codes, checkout custom fields, and billing. All key-authenticated; tenant-scoped to the agent.

```python
# Transactions: full history, CSV export, + actions
txs = agent.get_transactions(status="C", limit=50)
csv = agent.download_transactions(date_from="2026-01-01")     # raw CSV text
agent.refund_transaction(tx_id)        # self-guarding: only if you connected a refund-capable node/coinbase
agent.resend_webhook(tx_id)
agent.submit_hash(tx_id, "0xabc...")

# Stores (sub-merchants)
store = agent.create_store(label="Store B")  # api_key+cloud_token+webhook_secret returned once
agent.rotate_store_credential(store["store"]["id"], "cloud_token")

# Shop products, landers, payout-info/OTC
agent.create_shop_product(title="Ebook", price=9.99, currency="USD")
agent.create_lander(checkout_id=flag_id)
agent.create_payout_info(amount=50, currency="USD", email="payee@x.dev")  # emails the payee a link

# Discount codes (amount = price multiplier: 0.9 = 10% off) + checkout custom fields
agent.add_discount_code(code="LAUNCH", amount=0.9, checkout_ids="all")
agent.add_custom_field(type="select", label="Size", options=["S", "M", "L"])

# Billing: balances + capacity
bill = agent.get_billing()             # {credit_balance, ucash_points, lander_slots:{...}}
agent.buy_lander_pack(10)              # debits credit_balance, grows slots
agent.redeem_ucash(1000)               # UCASH points -> fee credit
```

## API

| Method | Auth | Description |
|---|---|---|
| `signup(email, password, primary_wallet=None)` | - | Register; returns `api_key` |
| `top_up(amount)` | key | Create a ≥$1 top-up checkout (adds platform credit; activates if not yet) |
| `get_agent()` | key | Account snapshot (balance, wallets, webhook, earnings summary) |
| `set_webhook(url)` | key | Set the settlement webhook |
| `set_wallet(asset, address)` | key | Set your receive address for an asset |
| `set_stripe(secret_key, product_id, webhook_secret, publishable_key=None)` | key | Connect your Stripe account (card rail); verifies the key + product |
| `get_stripe()` | key | Masked Stripe config + the webhook endpoint to register |
| `clear_stripe()` | key | Disconnect your Stripe account |
| `set_custom_token(type, code, contract_address, decimals, name, rate=None, rate_url=None)` | key | Add a custom token (ERC-20/TRC-20/SPL); then `set_wallet(asset=code, address=...)` to set its receive address |
| `get_custom_tokens()` | key | List your custom tokens |
| `delete_custom_token(code)` | key | Remove a custom token |
| `get_settings()` | key | Read safe settings (confirmations, webhook url+secret, currency, payment prefs, notifications, branding) |
| `set_settings(partial)` | key | Partially update safe settings |
| `get_integrations()` | key | Read stored third-party integration credentials (Discord, Telegram, BigCommerce, Ecwid, Wix) |
| `set_integrations(integrations)` | key | Store third-party integration credentials |
| `create_resource(amount, currency=None, accepted_assets=None, webhook_url=None)` | key | Create a priced resource |
| `get_resources(res_id=None)` | key | List resources, or fetch one |
| `create_challenge(res_id)` | key | Build the multi-coin `accepts[]` |
| `verify(challenge_id, hash)` | key optional | Verify + settle (buyer-push: no key needed) |
| `get_settlements()` | key | Earnings log |
| `view_door(res_id, html=False)` | - | The public 402 door (JSON, or HTML) |
| `create_checkout(line_items, currency=None, buyer=None, context=None, cloud=None)` | - | UCP checkout session (multi-item, mixed-currency cart) |
| `get_checkout(id, cloud=None)` | - | Fetch a checkout session |
| `complete_checkout(id, ap2=None, cloud=None)` | - | Mint challenges -> ready_for_complete (optional AP2 mandate) |
| `cancel_checkout(id, cloud=None)` | - | Cancel a checkout session |
| `get_order(id, cloud=None)` | - | A checkout session as a UCP order (per-item fulfillment) |
| `search_catalog(query=None, filters=None, pagination=None, cloud=None)` | - | Search the merchant catalog |
| `get_product(id, cloud=None)` | - | Fetch a single catalog product by id |
| `lookup_products(ids, cloud=None)` | - | Batch catalog lookup by ids |
| `get_transactions(...)` / `get_transaction(id, webhook_log=False)` / `download_transactions(...)` | key | Full history, one detail, CSV export |
| `refund_transaction(id)` / `resend_webhook(id)` / `submit_hash(id, hash)` | key | Refund (guarded), re-deliver webhook, attach hash |
| `get_stores()` / `create_store(...)` / `update_store(id, ...)` / `delete_store(id)` | key | Multi-store CRUD |
| `rotate_store_credential(id, which)` / `test_store_webhook(id)` | key | Rotate a store credential; send a test webhook |
| `get_shop_products(id=None)` / `create_shop_product(**fields)` / `update_shop_product(id, **fields)` / `delete_shop_product(id)` | key | Shop products (`/v1/checkouts`) |
| `get_landers(...)` / `create_lander(checkout_id, tpl=None)` / `update_lander(...)` / `delete_lander(id)` | key | Landers + offer status |
| `create_payout_info(...)` / `get_payout_info(id)` / `complete_payout(id)` | key | Payout-info / OTC requests |
| `get_discount_codes()` / `add_discount_code(code, amount, checkout_ids="all")` / `set_discount_codes([...])` / `delete_discount_code(code)` | key | Discount codes (amount = multiplier) |
| `get_custom_fields()` / `add_custom_field(**field)` / `set_custom_fields(custom_fields, title=None)` / `delete_custom_field(index)` | key | Checkout custom fields |
| `get_billing()` / `buy_lander_pack(qty)` / `redeem_ucash(amount)` | key | Balances + capacity (lander pack, UCASH redeem) |

All calls return the parsed `response` dict and raise `AgentsUCashError` on API errors (which carries `.code` and `.status`).

## Error handling

```python
from agents_u_cash import AgentsUCash, AgentsUCashError

try:
    agent.create_resource(amount=0.05)
except AgentsUCashError as e:
    print(e.code, e.status, e)   # e.g. 'uxc_agent_not_activated' 402 ...
```

Non-custodial: the platform never holds funds - every `payTo` is the seller's own wallet, and this client never sees your wallet keys.
