agents-u-cash 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: agents-u-cash
3
+ Version: 0.1.0
4
+ Summary: Zero-dependency Python client for the agents.u.cash 402 Online Protocol API — non-custodial agent payments (buy + sell).
5
+ Author: U.CASH Pay
6
+ License: MIT
7
+ Project-URL: Homepage, https://agents.u.cash
8
+ Project-URL: Repository, https://github.com/ageesen/pay-u-cash
9
+ Keywords: agents.u.cash,x402,402,payments,crypto,non-custodial,ai-agents
10
+ Requires-Python: >=3.7
11
+ Description-Content-Type: text/markdown
12
+
13
+ # agents-u-cash (Python)
14
+
15
+ 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, push-verify a payment).
16
+
17
+ Uses only the standard library (`urllib`). No dependencies. Python 3.7+.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install agents-u-cash
23
+ ```
24
+
25
+ Or copy `agents_u_cash.py` — it has no dependencies.
26
+
27
+ ## Sell (as an agent)
28
+
29
+ ```python
30
+ from agents_u_cash import AgentsUCash
31
+
32
+ # Get an API key once (wallet-first; then top up >= $1 to activate):
33
+ # key = AgentsUCash().signup(email="me@agent.dev", password="longpass")["api_key"]
34
+
35
+ agent = AgentsUCash(api_key="...")
36
+ agent.set_wallet("btc", "bc1q…")
37
+ agent.set_webhook("https://my.bot/webhook")
38
+
39
+ res = agent.create_resource(amount=0.05) # priced resource
40
+ acc = agent.create_challenge(res["res_id"]) # what a buyer pays
41
+ # Share the payable link: https://agents.u.cash/r/{res_id}
42
+
43
+ settled = agent.get_settlements() # your earnings log
44
+ ```
45
+
46
+ ## Buy (as a buyer)
47
+
48
+ ```python
49
+ from agents_u_cash import AgentsUCash
50
+
51
+ buyer = AgentsUCash() # no key needed to buy
52
+ door = buyer.view_door(res_id) # the 402 door (JSON)
53
+ # 1. pick an entry, pay entry["payTo"] exactly entry["amount"] from your wallet (out of band)
54
+ # 2. push-verify with the on-chain tx hash:
55
+ result = buyer.verify(door["accepts"][0]["challengeId"], tx_hash)
56
+ # -> {"settled": True} | {"status": "pending", "confirmations": n, "required": m}
57
+ ```
58
+
59
+ A human-friendly payable page is also available: `buyer.view_door(res_id, html=True)` returns the HTML.
60
+
61
+ ## API
62
+
63
+ | Method | Auth | Description |
64
+ |---|---|---|
65
+ | `signup(email, password, primary_wallet=None)` | — | Register; returns `api_key` |
66
+ | `top_up(amount)` | key | Create a ≥$1 top-up checkout (activates the account) |
67
+ | `get_agent()` | key | Account snapshot (balance, wallets, webhook, earnings summary) |
68
+ | `set_webhook(url)` | key | Set the settlement webhook |
69
+ | `set_wallet(asset, address)` | key | Set your receive address for an asset |
70
+ | `set_stripe(secret_key, product_id, webhook_secret, publishable_key=None)` | key | Connect your Stripe account (card rail); verifies the key + product |
71
+ | `get_stripe()` | key | Masked Stripe config + the webhook endpoint to register |
72
+ | `clear_stripe()` | key | Disconnect your Stripe account |
73
+ | `create_resource(amount, currency=None, accepted_assets=None, webhook_url=None)` | key | Create a priced resource |
74
+ | `get_resources(res_id=None)` | key | List resources, or fetch one |
75
+ | `create_challenge(res_id)` | key | Build the multi-coin `accepts[]` |
76
+ | `verify(challenge_id, hash)` | key optional | Verify + settle (buyer-push: no key needed) |
77
+ | `get_settlements()` | key | Earnings log |
78
+ | `view_door(res_id, html=False)` | — | The public 402 door (JSON, or HTML) |
79
+
80
+ All calls return the parsed `response` dict and raise `AgentsUCashError` on API errors (which carries `.code` and `.status`).
81
+
82
+ ## Error handling
83
+
84
+ ```python
85
+ from agents_u_cash import AgentsUCash, AgentsUCashError
86
+
87
+ try:
88
+ agent.create_resource(amount=0.05)
89
+ except AgentsUCashError as e:
90
+ print(e.code, e.status, e) # e.g. 'uxc_agent_not_activated' 402 ...
91
+ ```
92
+
93
+ Non-custodial: the platform never holds funds — every `payTo` is the seller's own wallet, and this client never sees your wallet keys.
@@ -0,0 +1,81 @@
1
+ # agents-u-cash (Python)
2
+
3
+ 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, push-verify a payment).
4
+
5
+ Uses only the standard library (`urllib`). No dependencies. Python 3.7+.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install agents-u-cash
11
+ ```
12
+
13
+ Or copy `agents_u_cash.py` — it has no dependencies.
14
+
15
+ ## Sell (as an agent)
16
+
17
+ ```python
18
+ from agents_u_cash import AgentsUCash
19
+
20
+ # Get an API key once (wallet-first; then top up >= $1 to activate):
21
+ # key = AgentsUCash().signup(email="me@agent.dev", password="longpass")["api_key"]
22
+
23
+ agent = AgentsUCash(api_key="...")
24
+ agent.set_wallet("btc", "bc1q…")
25
+ agent.set_webhook("https://my.bot/webhook")
26
+
27
+ res = agent.create_resource(amount=0.05) # priced resource
28
+ acc = agent.create_challenge(res["res_id"]) # what a buyer pays
29
+ # Share the payable link: https://agents.u.cash/r/{res_id}
30
+
31
+ settled = agent.get_settlements() # your earnings log
32
+ ```
33
+
34
+ ## Buy (as a buyer)
35
+
36
+ ```python
37
+ from agents_u_cash import AgentsUCash
38
+
39
+ buyer = AgentsUCash() # no key needed to buy
40
+ door = buyer.view_door(res_id) # the 402 door (JSON)
41
+ # 1. pick an entry, pay entry["payTo"] exactly entry["amount"] from your wallet (out of band)
42
+ # 2. push-verify with the on-chain tx hash:
43
+ result = buyer.verify(door["accepts"][0]["challengeId"], tx_hash)
44
+ # -> {"settled": True} | {"status": "pending", "confirmations": n, "required": m}
45
+ ```
46
+
47
+ A human-friendly payable page is also available: `buyer.view_door(res_id, html=True)` returns the HTML.
48
+
49
+ ## API
50
+
51
+ | Method | Auth | Description |
52
+ |---|---|---|
53
+ | `signup(email, password, primary_wallet=None)` | — | Register; returns `api_key` |
54
+ | `top_up(amount)` | key | Create a ≥$1 top-up checkout (activates the account) |
55
+ | `get_agent()` | key | Account snapshot (balance, wallets, webhook, earnings summary) |
56
+ | `set_webhook(url)` | key | Set the settlement webhook |
57
+ | `set_wallet(asset, address)` | key | Set your receive address for an asset |
58
+ | `set_stripe(secret_key, product_id, webhook_secret, publishable_key=None)` | key | Connect your Stripe account (card rail); verifies the key + product |
59
+ | `get_stripe()` | key | Masked Stripe config + the webhook endpoint to register |
60
+ | `clear_stripe()` | key | Disconnect your Stripe account |
61
+ | `create_resource(amount, currency=None, accepted_assets=None, webhook_url=None)` | key | Create a priced resource |
62
+ | `get_resources(res_id=None)` | key | List resources, or fetch one |
63
+ | `create_challenge(res_id)` | key | Build the multi-coin `accepts[]` |
64
+ | `verify(challenge_id, hash)` | key optional | Verify + settle (buyer-push: no key needed) |
65
+ | `get_settlements()` | key | Earnings log |
66
+ | `view_door(res_id, html=False)` | — | The public 402 door (JSON, or HTML) |
67
+
68
+ All calls return the parsed `response` dict and raise `AgentsUCashError` on API errors (which carries `.code` and `.status`).
69
+
70
+ ## Error handling
71
+
72
+ ```python
73
+ from agents_u_cash import AgentsUCash, AgentsUCashError
74
+
75
+ try:
76
+ agent.create_resource(amount=0.05)
77
+ except AgentsUCashError as e:
78
+ print(e.code, e.status, e) # e.g. 'uxc_agent_not_activated' 402 ...
79
+ ```
80
+
81
+ Non-custodial: the platform never holds funds — every `payTo` is the seller's own wallet, and this client never sees your wallet keys.
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: agents-u-cash
3
+ Version: 0.1.0
4
+ Summary: Zero-dependency Python client for the agents.u.cash 402 Online Protocol API — non-custodial agent payments (buy + sell).
5
+ Author: U.CASH Pay
6
+ License: MIT
7
+ Project-URL: Homepage, https://agents.u.cash
8
+ Project-URL: Repository, https://github.com/ageesen/pay-u-cash
9
+ Keywords: agents.u.cash,x402,402,payments,crypto,non-custodial,ai-agents
10
+ Requires-Python: >=3.7
11
+ Description-Content-Type: text/markdown
12
+
13
+ # agents-u-cash (Python)
14
+
15
+ 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, push-verify a payment).
16
+
17
+ Uses only the standard library (`urllib`). No dependencies. Python 3.7+.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install agents-u-cash
23
+ ```
24
+
25
+ Or copy `agents_u_cash.py` — it has no dependencies.
26
+
27
+ ## Sell (as an agent)
28
+
29
+ ```python
30
+ from agents_u_cash import AgentsUCash
31
+
32
+ # Get an API key once (wallet-first; then top up >= $1 to activate):
33
+ # key = AgentsUCash().signup(email="me@agent.dev", password="longpass")["api_key"]
34
+
35
+ agent = AgentsUCash(api_key="...")
36
+ agent.set_wallet("btc", "bc1q…")
37
+ agent.set_webhook("https://my.bot/webhook")
38
+
39
+ res = agent.create_resource(amount=0.05) # priced resource
40
+ acc = agent.create_challenge(res["res_id"]) # what a buyer pays
41
+ # Share the payable link: https://agents.u.cash/r/{res_id}
42
+
43
+ settled = agent.get_settlements() # your earnings log
44
+ ```
45
+
46
+ ## Buy (as a buyer)
47
+
48
+ ```python
49
+ from agents_u_cash import AgentsUCash
50
+
51
+ buyer = AgentsUCash() # no key needed to buy
52
+ door = buyer.view_door(res_id) # the 402 door (JSON)
53
+ # 1. pick an entry, pay entry["payTo"] exactly entry["amount"] from your wallet (out of band)
54
+ # 2. push-verify with the on-chain tx hash:
55
+ result = buyer.verify(door["accepts"][0]["challengeId"], tx_hash)
56
+ # -> {"settled": True} | {"status": "pending", "confirmations": n, "required": m}
57
+ ```
58
+
59
+ A human-friendly payable page is also available: `buyer.view_door(res_id, html=True)` returns the HTML.
60
+
61
+ ## API
62
+
63
+ | Method | Auth | Description |
64
+ |---|---|---|
65
+ | `signup(email, password, primary_wallet=None)` | — | Register; returns `api_key` |
66
+ | `top_up(amount)` | key | Create a ≥$1 top-up checkout (activates the account) |
67
+ | `get_agent()` | key | Account snapshot (balance, wallets, webhook, earnings summary) |
68
+ | `set_webhook(url)` | key | Set the settlement webhook |
69
+ | `set_wallet(asset, address)` | key | Set your receive address for an asset |
70
+ | `set_stripe(secret_key, product_id, webhook_secret, publishable_key=None)` | key | Connect your Stripe account (card rail); verifies the key + product |
71
+ | `get_stripe()` | key | Masked Stripe config + the webhook endpoint to register |
72
+ | `clear_stripe()` | key | Disconnect your Stripe account |
73
+ | `create_resource(amount, currency=None, accepted_assets=None, webhook_url=None)` | key | Create a priced resource |
74
+ | `get_resources(res_id=None)` | key | List resources, or fetch one |
75
+ | `create_challenge(res_id)` | key | Build the multi-coin `accepts[]` |
76
+ | `verify(challenge_id, hash)` | key optional | Verify + settle (buyer-push: no key needed) |
77
+ | `get_settlements()` | key | Earnings log |
78
+ | `view_door(res_id, html=False)` | — | The public 402 door (JSON, or HTML) |
79
+
80
+ All calls return the parsed `response` dict and raise `AgentsUCashError` on API errors (which carries `.code` and `.status`).
81
+
82
+ ## Error handling
83
+
84
+ ```python
85
+ from agents_u_cash import AgentsUCash, AgentsUCashError
86
+
87
+ try:
88
+ agent.create_resource(amount=0.05)
89
+ except AgentsUCashError as e:
90
+ print(e.code, e.status, e) # e.g. 'uxc_agent_not_activated' 402 ...
91
+ ```
92
+
93
+ Non-custodial: the platform never holds funds — every `payTo` is the seller's own wallet, and this client never sees your wallet keys.
@@ -0,0 +1,7 @@
1
+ README.md
2
+ agents_u_cash.py
3
+ pyproject.toml
4
+ agents_u_cash.egg-info/PKG-INFO
5
+ agents_u_cash.egg-info/SOURCES.txt
6
+ agents_u_cash.egg-info/dependency_links.txt
7
+ agents_u_cash.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ agents_u_cash
@@ -0,0 +1,155 @@
1
+ """agents.u.cash Python client — the 402 Online Protocol API (non-custodial agent payments).
2
+
3
+ Zero dependencies (stdlib ``urllib`` only; Python 3.7+). Works for both sides of the network: an
4
+ agent SELLING (manage resources, watch settlements) and a BUYER (fetch a 402 door, push-verify a
5
+ payment). See https://agents.u.cash.
6
+ """
7
+
8
+ import json
9
+ import urllib.request
10
+ import urllib.error
11
+ from urllib.parse import urlencode, quote
12
+
13
+ DEFAULT_BASE_URL = "https://agents.u.cash"
14
+ USER_AGENT = "agents-u-cash-python/0.1 (+https://agents.u.cash)"
15
+
16
+
17
+ class AgentsUCashError(Exception):
18
+ """Raised on any non-success API response. Carries ``code`` and ``status``."""
19
+
20
+ def __init__(self, message, code=None, status=None):
21
+ super().__init__(message)
22
+ self.code = code
23
+ self.status = status
24
+
25
+
26
+ class AgentsUCash:
27
+ """Client for the agents.u.cash API.
28
+
29
+ Most calls require an agent API key (from :meth:`signup`). The buyer-side calls
30
+ (:meth:`view_door` and the buyer form of :meth:`verify`) are public; a client constructed
31
+ without an api_key can call them.
32
+
33
+ Args:
34
+ api_key: Agent API key (required for seller/authenticated calls).
35
+ base_url: Override the API base URL.
36
+ """
37
+
38
+ def __init__(self, api_key="", base_url=DEFAULT_BASE_URL):
39
+ self.api_key = api_key
40
+ self.base_url = base_url.rstrip("/")
41
+
42
+ def _request(self, method, path, body=None, query=None, auth=True):
43
+ url = self.base_url + path
44
+ if query:
45
+ url += "?" + urlencode(query)
46
+ headers = {"Accept": "application/json", "User-Agent": USER_AGENT}
47
+ data = None
48
+ if auth and self.api_key:
49
+ headers["X-Api-Key"] = self.api_key
50
+ if body is not None:
51
+ headers["Content-Type"] = "application/json"
52
+ data = json.dumps(body).encode("utf-8")
53
+ req = urllib.request.Request(url, data=data, headers=headers, method=method)
54
+ try:
55
+ with urllib.request.urlopen(req) as resp:
56
+ text = resp.read().decode("utf-8")
57
+ status = resp.status
58
+ except urllib.error.HTTPError as e:
59
+ text = e.read().decode("utf-8")
60
+ status = e.code
61
+ try:
62
+ payload = json.loads(text) if text else {}
63
+ except ValueError:
64
+ payload = {"success": False, "message": text}
65
+ if not payload or payload.get("success") is not True:
66
+ raise AgentsUCashError(
67
+ payload.get("message", "HTTP %s" % status),
68
+ code=payload.get("error_code", "http_error"),
69
+ status=status,
70
+ )
71
+ return payload["response"]
72
+
73
+ # ----- account -----
74
+ def signup(self, email, password, primary_wallet=None):
75
+ """Register an agent account. Wallet-first: returns the api_key immediately."""
76
+ body = {"email": email, "password": password}
77
+ if primary_wallet is not None:
78
+ body["primary_wallet"] = primary_wallet
79
+ return self._request("POST", "/v1/signup", body=body, auth=False)
80
+
81
+ def top_up(self, amount):
82
+ """Create a credit top-up checkout ($1 min; activates the account on confirmation)."""
83
+ return self._request("POST", "/v1/top-up", body={"amount": amount})
84
+
85
+ def get_agent(self):
86
+ """Account snapshot: activation, balance, wallets, webhook URL, earnings summary."""
87
+ return self._request("GET", "/v1/agent")
88
+
89
+ def set_webhook(self, webhook_url):
90
+ """Set the webhook URL notified on settlement."""
91
+ return self._request("POST", "/v1/agent", body={"webhook_url": webhook_url})
92
+
93
+ def set_wallet(self, asset, address):
94
+ """Set the agent's own receive address for an asset (where buyer funds land)."""
95
+ return self._request("POST", "/v1/wallets", body={"asset": asset, "address": address})
96
+
97
+ def set_stripe(self, secret_key, product_id, webhook_secret, publishable_key=None):
98
+ """Connect the agent's own Stripe account to enable card payments (the redirect rail)."""
99
+ body = {"secret_key": secret_key, "product_id": product_id, "webhook_secret": webhook_secret}
100
+ if publishable_key is not None:
101
+ body["publishable_key"] = publishable_key
102
+ return self._request("POST", "/v1/stripe", body=body)
103
+
104
+ def get_stripe(self):
105
+ """The masked Stripe config + the webhook endpoint URL to register in the Stripe dashboard."""
106
+ return self._request("GET", "/v1/stripe")
107
+
108
+ def clear_stripe(self):
109
+ """Disconnect the agent's Stripe account (disables card payments)."""
110
+ return self._request("POST", "/v1/stripe", body={"clear": 1})
111
+
112
+ # ----- resources (seller) -----
113
+ def create_resource(self, amount, currency=None, accepted_assets=None, webhook_url=None):
114
+ """Create a priced resource. Returns {res_id, amount, currency, accepted_assets}."""
115
+ body = {"amount": amount}
116
+ if currency is not None:
117
+ body["currency"] = currency
118
+ if accepted_assets is not None:
119
+ body["accepted_assets"] = accepted_assets
120
+ if webhook_url is not None:
121
+ body["webhook_url"] = webhook_url
122
+ return self._request("POST", "/v1/resources", body=body)
123
+
124
+ def get_resources(self, res_id=None):
125
+ """List the agent's resources, or fetch one by res_id."""
126
+ return self._request("GET", "/v1/resources", query={"res_id": res_id} if res_id else None)
127
+
128
+ # ----- 402 payment flow -----
129
+ def create_challenge(self, res_id):
130
+ """Build the multi-coin accepts[] for a resource (the payable options)."""
131
+ return self._request("POST", "/v1/challenge", body={"res_id": res_id})
132
+
133
+ def verify(self, challenge_id, hash):
134
+ """Verify + settle a payment by on-chain tx hash.
135
+
136
+ Buyer-push: with no api_key on the client, the public challengeId authorizes the call
137
+ (settlement is still gated by on-chain confirmation).
138
+ """
139
+ return self._request(
140
+ "POST", "/v1/verify", body={"challengeId": challenge_id, "hash": hash}, auth=bool(self.api_key)
141
+ )
142
+
143
+ def get_settlements(self):
144
+ """The agent's earnings log (settled/underpaid resource payments)."""
145
+ return self._request("GET", "/v1/settlements")
146
+
147
+ # ----- buyer / public -----
148
+ def view_door(self, res_id, html=False):
149
+ """The public 402 door: price + multi-coin accepts[]. Pass html=True for the payable page."""
150
+ if html:
151
+ url = self.base_url + "/r/" + quote(res_id)
152
+ req = urllib.request.Request(url, headers={"Accept": "text/html", "User-Agent": USER_AGENT})
153
+ with urllib.request.urlopen(req) as resp:
154
+ return resp.read().decode("utf-8")
155
+ return self._request("GET", "/r/" + quote(res_id), auth=False)
@@ -0,0 +1,20 @@
1
+ [project]
2
+ name = "agents-u-cash"
3
+ version = "0.1.0"
4
+ description = "Zero-dependency Python client for the agents.u.cash 402 Online Protocol API — non-custodial agent payments (buy + sell)."
5
+ readme = "README.md"
6
+ requires-python = ">=3.7"
7
+ license = { text = "MIT" }
8
+ authors = [{ name = "U.CASH Pay" }]
9
+ keywords = ["agents.u.cash", "x402", "402", "payments", "crypto", "non-custodial", "ai-agents"]
10
+
11
+ [project.urls]
12
+ Homepage = "https://agents.u.cash"
13
+ Repository = "https://github.com/ageesen/pay-u-cash"
14
+
15
+ [build-system]
16
+ requires = ["setuptools>=61"]
17
+ build-backend = "setuptools.build_meta"
18
+
19
+ [tool.setuptools]
20
+ py-modules = ["agents_u_cash"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+