openclaw-algorand-plugin 0.5.0

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.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -0
  3. package/index.ts +361 -0
  4. package/lib/mcp-servers.ts +14 -0
  5. package/lib/x402-fetch.ts +213 -0
  6. package/memory/algorand-plugin.md +82 -0
  7. package/openclaw.plugin.json +30 -0
  8. package/package.json +38 -0
  9. package/setup.ts +80 -0
  10. package/skills/algorand-development/SKILL.md +90 -0
  11. package/skills/algorand-development/references/build-smart-contracts-reference.md +79 -0
  12. package/skills/algorand-development/references/build-smart-contracts.md +52 -0
  13. package/skills/algorand-development/references/create-project-reference.md +86 -0
  14. package/skills/algorand-development/references/create-project.md +89 -0
  15. package/skills/algorand-development/references/implement-arc-standards-arc32-arc56.md +396 -0
  16. package/skills/algorand-development/references/implement-arc-standards-arc4.md +265 -0
  17. package/skills/algorand-development/references/implement-arc-standards.md +92 -0
  18. package/skills/algorand-development/references/search-algorand-examples-reference.md +119 -0
  19. package/skills/algorand-development/references/search-algorand-examples.md +89 -0
  20. package/skills/algorand-development/references/troubleshoot-errors-contract.md +373 -0
  21. package/skills/algorand-development/references/troubleshoot-errors-transaction.md +599 -0
  22. package/skills/algorand-development/references/troubleshoot-errors.md +105 -0
  23. package/skills/algorand-development/references/use-algokit-cli-reference.md +228 -0
  24. package/skills/algorand-development/references/use-algokit-cli.md +64 -0
  25. package/skills/algorand-interaction/SKILL.md +223 -0
  26. package/skills/algorand-interaction/references/algorand-mcp.md +743 -0
  27. package/skills/algorand-interaction/references/examples-algorand-mcp.md +647 -0
  28. package/skills/algorand-python/SKILL.md +95 -0
  29. package/skills/algorand-python/references/build-smart-contracts-decorators.md +413 -0
  30. package/skills/algorand-python/references/build-smart-contracts-reference.md +55 -0
  31. package/skills/algorand-python/references/build-smart-contracts-storage.md +452 -0
  32. package/skills/algorand-python/references/build-smart-contracts-transactions.md +445 -0
  33. package/skills/algorand-python/references/build-smart-contracts-types.md +438 -0
  34. package/skills/algorand-python/references/build-smart-contracts.md +82 -0
  35. package/skills/algorand-python/references/create-project-reference.md +55 -0
  36. package/skills/algorand-python/references/create-project.md +75 -0
  37. package/skills/algorand-python/references/implement-arc-standards-arc32-arc56.md +101 -0
  38. package/skills/algorand-python/references/implement-arc-standards-arc4.md +154 -0
  39. package/skills/algorand-python/references/implement-arc-standards.md +39 -0
  40. package/skills/algorand-python/references/troubleshoot-errors-contract.md +355 -0
  41. package/skills/algorand-python/references/troubleshoot-errors-transaction.md +430 -0
  42. package/skills/algorand-python/references/troubleshoot-errors.md +46 -0
  43. package/skills/algorand-python/references/use-algokit-utils-reference.md +350 -0
  44. package/skills/algorand-python/references/use-algokit-utils.md +76 -0
  45. package/skills/algorand-typescript/SKILL.md +131 -0
  46. package/skills/algorand-typescript/references/algorand-ts-migration-from-beta.md +448 -0
  47. package/skills/algorand-typescript/references/algorand-ts-migration-from-tealscript.md +487 -0
  48. package/skills/algorand-typescript/references/algorand-ts-migration.md +102 -0
  49. package/skills/algorand-typescript/references/algorand-typescript-syntax-methods-and-abi.md +134 -0
  50. package/skills/algorand-typescript/references/algorand-typescript-syntax-reference.md +58 -0
  51. package/skills/algorand-typescript/references/algorand-typescript-syntax-storage.md +154 -0
  52. package/skills/algorand-typescript/references/algorand-typescript-syntax-transactions.md +187 -0
  53. package/skills/algorand-typescript/references/algorand-typescript-syntax-types-and-values.md +150 -0
  54. package/skills/algorand-typescript/references/algorand-typescript-syntax.md +84 -0
  55. package/skills/algorand-typescript/references/build-smart-contracts-reference.md +52 -0
  56. package/skills/algorand-typescript/references/build-smart-contracts.md +74 -0
  57. package/skills/algorand-typescript/references/call-smart-contracts-reference.md +237 -0
  58. package/skills/algorand-typescript/references/call-smart-contracts.md +183 -0
  59. package/skills/algorand-typescript/references/create-project-reference.md +53 -0
  60. package/skills/algorand-typescript/references/create-project.md +86 -0
  61. package/skills/algorand-typescript/references/deploy-react-frontend-examples.md +527 -0
  62. package/skills/algorand-typescript/references/deploy-react-frontend-reference.md +412 -0
  63. package/skills/algorand-typescript/references/deploy-react-frontend.md +239 -0
  64. package/skills/algorand-typescript/references/implement-arc-standards-arc32-arc56.md +73 -0
  65. package/skills/algorand-typescript/references/implement-arc-standards-arc4.md +126 -0
  66. package/skills/algorand-typescript/references/implement-arc-standards.md +44 -0
  67. package/skills/algorand-typescript/references/test-smart-contracts-examples.md +245 -0
  68. package/skills/algorand-typescript/references/test-smart-contracts-unit-tests.md +147 -0
  69. package/skills/algorand-typescript/references/test-smart-contracts.md +127 -0
  70. package/skills/algorand-typescript/references/troubleshoot-errors-contract.md +296 -0
  71. package/skills/algorand-typescript/references/troubleshoot-errors-transaction.md +438 -0
  72. package/skills/algorand-typescript/references/troubleshoot-errors.md +56 -0
  73. package/skills/algorand-typescript/references/use-algokit-utils-reference.md +342 -0
  74. package/skills/algorand-typescript/references/use-algokit-utils.md +74 -0
  75. package/skills/algorand-x402-python/SKILL.md +113 -0
  76. package/skills/algorand-x402-python/references/create-python-x402-client-examples.md +469 -0
  77. package/skills/algorand-x402-python/references/create-python-x402-client-reference.md +313 -0
  78. package/skills/algorand-x402-python/references/create-python-x402-client.md +207 -0
  79. package/skills/algorand-x402-python/references/create-python-x402-facilitator-examples.md +924 -0
  80. package/skills/algorand-x402-python/references/create-python-x402-facilitator-reference.md +629 -0
  81. package/skills/algorand-x402-python/references/create-python-x402-facilitator.md +408 -0
  82. package/skills/algorand-x402-python/references/create-python-x402-server-examples.md +703 -0
  83. package/skills/algorand-x402-python/references/create-python-x402-server-reference.md +303 -0
  84. package/skills/algorand-x402-python/references/create-python-x402-server.md +221 -0
  85. package/skills/algorand-x402-python/references/explain-algorand-x402-python-examples.md +605 -0
  86. package/skills/algorand-x402-python/references/explain-algorand-x402-python-reference.md +315 -0
  87. package/skills/algorand-x402-python/references/explain-algorand-x402-python.md +167 -0
  88. package/skills/algorand-x402-python/references/use-python-x402-core-avm-examples.md +554 -0
  89. package/skills/algorand-x402-python/references/use-python-x402-core-avm-reference.md +278 -0
  90. package/skills/algorand-x402-python/references/use-python-x402-core-avm.md +166 -0
  91. package/skills/algorand-x402-typescript/SKILL.md +129 -0
  92. package/skills/algorand-x402-typescript/references/create-typescript-x402-client-examples.md +879 -0
  93. package/skills/algorand-x402-typescript/references/create-typescript-x402-client-reference.md +371 -0
  94. package/skills/algorand-x402-typescript/references/create-typescript-x402-client.md +236 -0
  95. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-examples.md +875 -0
  96. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-reference.md +461 -0
  97. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator.md +270 -0
  98. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-examples.md +1181 -0
  99. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-reference.md +360 -0
  100. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs.md +251 -0
  101. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-examples.md +870 -0
  102. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-reference.md +323 -0
  103. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall.md +281 -0
  104. package/skills/algorand-x402-typescript/references/create-typescript-x402-server-examples.md +1135 -0
  105. package/skills/algorand-x402-typescript/references/create-typescript-x402-server-reference.md +382 -0
  106. package/skills/algorand-x402-typescript/references/create-typescript-x402-server.md +216 -0
  107. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-examples.md +616 -0
  108. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-reference.md +323 -0
  109. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript.md +232 -0
  110. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-examples.md +1417 -0
  111. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-reference.md +504 -0
  112. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm.md +158 -0
@@ -0,0 +1,313 @@
1
+ # x402 Python HTTP Client Reference
2
+
3
+ Detailed API reference for httpx (async) and requests (sync) client integrations in the `x402-avm` Python package.
4
+
5
+ ## httpx APIs
6
+
7
+ All httpx APIs are in `x402.http.clients.httpx`. They use `x402Client` (async).
8
+
9
+ ### `x402HttpxClient(x402_client, **kwargs)`
10
+
11
+ Convenience class extending `httpx.AsyncClient` with built-in payment transport.
12
+
13
+ | Parameter | Type | Description |
14
+ |-----------|------|-------------|
15
+ | `x402_client` | `x402Client \| x402HTTPClient` | The async x402 client instance |
16
+ | `**kwargs` | `Any` | Additional arguments forwarded to `httpx.AsyncClient` |
17
+
18
+ **Returns**: `httpx.AsyncClient` subclass with payment handling.
19
+
20
+ **Usage**:
21
+ ```python
22
+ async with x402HttpxClient(x402, timeout=30.0) as client:
23
+ response = await client.get(url)
24
+ ```
25
+
26
+ ### `wrapHttpxWithPayment(x402_client, **httpx_kwargs)`
27
+
28
+ Factory function that creates a new `httpx.AsyncClient` with payment transport.
29
+
30
+ | Parameter | Type | Description |
31
+ |-----------|------|-------------|
32
+ | `x402_client` | `x402Client \| x402HTTPClient` | The async x402 client instance |
33
+ | `**httpx_kwargs` | `Any` | Additional arguments forwarded to `httpx.AsyncClient` |
34
+
35
+ **Returns**: `httpx.AsyncClient` (standard instance, not subclass).
36
+
37
+ ### `wrapHttpxWithPaymentFromConfig(config, **httpx_kwargs)`
38
+
39
+ Creates an `httpx.AsyncClient` from a `x402ClientConfig` (builds `x402Client` internally).
40
+
41
+ | Parameter | Type | Description |
42
+ |-----------|------|-------------|
43
+ | `config` | `x402ClientConfig` | Configuration with scheme registrations |
44
+ | `**httpx_kwargs` | `Any` | Additional arguments forwarded to `httpx.AsyncClient` |
45
+
46
+ **Returns**: `httpx.AsyncClient` with payment transport.
47
+
48
+ ### `x402_httpx_transport(client, transport=None)`
49
+
50
+ Low-level function that returns an `x402AsyncTransport` for manual `httpx.AsyncClient` construction.
51
+
52
+ | Parameter | Type | Default | Description |
53
+ |-----------|------|---------|-------------|
54
+ | `client` | `x402Client \| x402HTTPClient` | required | The async x402 client |
55
+ | `transport` | `AsyncBaseTransport \| None` | `None` | Custom underlying transport |
56
+
57
+ **Returns**: `x402AsyncTransport` (an `httpx.AsyncBaseTransport`).
58
+
59
+ ### `x402AsyncTransport`
60
+
61
+ The transport implementation that intercepts 402 responses and handles payments.
62
+
63
+ | Parameter | Type | Default | Description |
64
+ |-----------|------|---------|-------------|
65
+ | `client` | `x402Client \| x402HTTPClient` | required | The async x402 client |
66
+ | `transport` | `AsyncBaseTransport \| None` | `None` | Custom underlying transport |
67
+
68
+ **Behavior**:
69
+ 1. Sends the original request via the underlying transport
70
+ 2. If response is 402, parses PaymentRequirements from headers/body
71
+ 3. Creates payment payload via the registered scheme
72
+ 4. Retries request with `PAYMENT-SIGNATURE` header
73
+ 5. If retry also returns 402, passes through as-is (no infinite loop)
74
+
75
+ ## requests APIs
76
+
77
+ All requests APIs are in `x402.http.clients.requests`. They use `x402ClientSync` (sync).
78
+
79
+ ### `x402_requests(client, **adapter_kwargs)`
80
+
81
+ Creates a new `requests.Session` with payment adapter pre-configured.
82
+
83
+ | Parameter | Type | Description |
84
+ |-----------|------|-------------|
85
+ | `client` | `x402ClientSync \| x402HTTPClientSync` | The sync x402 client instance |
86
+ | `**adapter_kwargs` | `Any` | Additional arguments forwarded to `x402HTTPAdapter` |
87
+
88
+ **Returns**: `requests.Session` with payment handling for `https://` and `http://`.
89
+
90
+ ### `wrapRequestsWithPayment(session, client, **adapter_kwargs)`
91
+
92
+ Wraps an existing `requests.Session` with payment adapter.
93
+
94
+ | Parameter | Type | Description |
95
+ |-----------|------|-------------|
96
+ | `session` | `requests.Session` | Existing session to wrap |
97
+ | `client` | `x402ClientSync \| x402HTTPClientSync` | The sync x402 client instance |
98
+ | `**adapter_kwargs` | `Any` | Additional arguments forwarded to `x402HTTPAdapter` |
99
+
100
+ **Returns**: Same `requests.Session` (mutated in place). Mounts adapter for `https://` and `http://`.
101
+
102
+ ### `wrapRequestsWithPaymentFromConfig(session, config, **adapter_kwargs)`
103
+
104
+ Wraps a session from a `x402ClientConfig` (builds `x402ClientSync` internally).
105
+
106
+ | Parameter | Type | Description |
107
+ |-----------|------|-------------|
108
+ | `session` | `requests.Session` | Existing session to wrap |
109
+ | `config` | `x402ClientConfig` | Configuration with scheme registrations |
110
+ | `**adapter_kwargs` | `Any` | Additional arguments forwarded to `x402HTTPAdapter` |
111
+
112
+ **Returns**: Same `requests.Session` with payment handling.
113
+
114
+ ### `x402_http_adapter(client, **kwargs)`
115
+
116
+ Low-level function that returns an `x402HTTPAdapter` for manual `session.mount()`.
117
+
118
+ | Parameter | Type | Description |
119
+ |-----------|------|-------------|
120
+ | `client` | `x402ClientSync \| x402HTTPClientSync` | The sync x402 client |
121
+ | `**kwargs` | `Any` | Additional arguments forwarded to `x402HTTPAdapter` |
122
+
123
+ **Returns**: `x402HTTPAdapter` (a `requests.adapters.HTTPAdapter`).
124
+
125
+ ### `x402HTTPAdapter`
126
+
127
+ The adapter implementation that intercepts 402 responses and handles payments.
128
+
129
+ | Parameter | Type | Description |
130
+ |-----------|------|-------------|
131
+ | `client` | `x402ClientSync \| x402HTTPClientSync` | The sync x402 client |
132
+ | `**kwargs` | `Any` | Forwarded to `HTTPAdapter.__init__` (e.g., `max_retries`, `pool_connections`) |
133
+
134
+ **Runtime check**: Raises `TypeError` if passed an async `x402Client` instead of `x402ClientSync`.
135
+
136
+ **Behavior**:
137
+ 1. Sends the original request via the standard HTTPAdapter
138
+ 2. If response is 402, parses PaymentRequirements from headers/body
139
+ 3. Creates payment payload synchronously via the registered scheme
140
+ 4. Clones request with `PAYMENT-SIGNATURE` header and `Payment-Retry: 1` marker
141
+ 5. Retries request; if retry returns 402, passes through as-is
142
+
143
+ ## ClientAvmSigner Implementation
144
+
145
+ The signer protocol that both httpx and requests clients depend on:
146
+
147
+ ```python
148
+ class ClientAvmSigner(Protocol):
149
+ @property
150
+ def address(self) -> str:
151
+ """58-character Algorand address."""
152
+ ...
153
+
154
+ def sign_transactions(
155
+ self,
156
+ unsigned_txns: list[bytes],
157
+ indexes_to_sign: list[int],
158
+ ) -> list[bytes | None]:
159
+ """Sign specified transactions in a group."""
160
+ ...
161
+ ```
162
+
163
+ ### Encoding Boundaries
164
+
165
+ The x402 SDK passes raw msgpack bytes. Python algosdk (v2.11.1) uses base64 strings. The conversion happens inside `sign_transactions()`:
166
+
167
+ | Direction | Code |
168
+ |-----------|------|
169
+ | Raw bytes to algosdk | `encoding.msgpack_decode(base64.b64encode(raw).decode())` |
170
+ | algosdk to raw bytes | `base64.b64decode(encoding.msgpack_encode(obj))` |
171
+ | Private key for signing | `base64.b64encode(secret_key).decode()` |
172
+
173
+ ### Complete Implementation
174
+
175
+ ```python
176
+ import base64
177
+ from algosdk import encoding
178
+
179
+
180
+ class AlgorandSigner:
181
+ def __init__(self, secret_key: bytes, address: str):
182
+ self._secret_key = secret_key
183
+ self._address = address
184
+
185
+ @property
186
+ def address(self) -> str:
187
+ return self._address
188
+
189
+ def sign_transactions(
190
+ self,
191
+ unsigned_txns: list[bytes],
192
+ indexes_to_sign: list[int],
193
+ ) -> list[bytes | None]:
194
+ sk_b64 = base64.b64encode(self._secret_key).decode()
195
+ result: list[bytes | None] = []
196
+ for i, txn_bytes in enumerate(unsigned_txns):
197
+ if i in indexes_to_sign:
198
+ txn = encoding.msgpack_decode(
199
+ base64.b64encode(txn_bytes).decode()
200
+ )
201
+ signed = txn.sign(sk_b64)
202
+ result.append(
203
+ base64.b64decode(encoding.msgpack_encode(signed))
204
+ )
205
+ else:
206
+ result.append(None)
207
+ return result
208
+ ```
209
+
210
+ ## Registration Functions
211
+
212
+ ### `register_exact_avm_client(client, signer, networks=None, algod_url=None)`
213
+
214
+ Registers AVM payment scheme on an x402 client (works with both async and sync).
215
+
216
+ | Parameter | Type | Default | Description |
217
+ |-----------|------|---------|-------------|
218
+ | `client` | `x402Client \| x402ClientSync` | required | The x402 client instance |
219
+ | `signer` | `ClientAvmSigner` | required | Signer implementation |
220
+ | `networks` | `str \| list[str] \| None` | `None` | Default: registers `"algorand:*"` wildcard + V1 names |
221
+ | `algod_url` | `str \| None` | `None` | Custom algod endpoint |
222
+
223
+ ### Network Registration Behavior
224
+
225
+ By default, `register_exact_avm_client` registers:
226
+ - V2: `"algorand:*"` wildcard (matches any Algorand CAIP-2 network)
227
+ - V1: All legacy network names (`"algorand-mainnet"`, `"algorand-testnet"`)
228
+
229
+ For specific networks:
230
+ ```python
231
+ register_exact_avm_client(x402, signer, networks="algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=")
232
+ ```
233
+
234
+ ## Error Classes
235
+
236
+ ### httpx Errors
237
+
238
+ | Error | Description |
239
+ |-------|-------------|
240
+ | `PaymentError` | Base class for all payment errors |
241
+ | `PaymentAlreadyAttemptedError` | Payment retry already attempted (prevents infinite loop) |
242
+ | `MissingRequestConfigError` | Missing request configuration |
243
+
244
+ ### requests Errors
245
+
246
+ | Error | Description |
247
+ |-------|-------------|
248
+ | `PaymentError` | Payment handling failed |
249
+ | `TypeError` | Passed async `x402Client` instead of `x402ClientSync` |
250
+
251
+ ## Environment Variables
252
+
253
+ | Variable | Description | Example |
254
+ |----------|-------------|---------|
255
+ | `AVM_PRIVATE_KEY` | Base64-encoded 64-byte key (32-byte seed + 32-byte pubkey) | `base64(seed \|\| pubkey)` |
256
+ | `RESOURCE_URL` | The paid endpoint URL | `https://api.example.com/paid` |
257
+ | `ALGOD_TESTNET_URL` | Custom algod testnet endpoint (optional) | `https://testnet-api.algonode.cloud` |
258
+ | `ALGOD_MAINNET_URL` | Custom algod mainnet endpoint (optional) | `https://mainnet-api.algonode.cloud` |
259
+
260
+ ### Private Key Format
261
+
262
+ The `AVM_PRIVATE_KEY` is a Base64-encoded 64-byte key:
263
+ - First 32 bytes: Ed25519 seed (private key)
264
+ - Last 32 bytes: Ed25519 public key
265
+ - Address derivation: `encoding.encode_address(secret_key[32:])`
266
+
267
+ ## Payment Flow
268
+
269
+ 1. The HTTP client sends a GET request to the resource URL
270
+ 2. If the server returns HTTP 402, the transport/adapter intercepts the response
271
+ 3. It parses the `PaymentRequired` data from response headers (V2) or body (V1)
272
+ 4. The registered `ExactAvmScheme` creates an atomic transaction group (ASA transfer) and signs it via the signer
273
+ 5. Payment headers are added to a retry request
274
+ 6. The server validates payment and returns the resource
275
+
276
+ ## Sync vs Async Comparison
277
+
278
+ | Feature | httpx (async) | requests (sync) |
279
+ |---------|---------------|-----------------|
280
+ | x402 Client | `x402Client` | `x402ClientSync` |
281
+ | Convenience | `x402HttpxClient(x402)` | `x402_requests(x402)` |
282
+ | Wrap existing | `wrapHttpxWithPayment(x402)` | `wrapRequestsWithPayment(session, x402)` |
283
+ | From config | `wrapHttpxWithPaymentFromConfig(config)` | `wrapRequestsWithPaymentFromConfig(session, config)` |
284
+ | Low-level | `x402_httpx_transport(x402)` | `x402_http_adapter(x402)` |
285
+ | Transport class | `x402AsyncTransport` | `x402HTTPAdapter` |
286
+ | Context manager | `async with ... as client:` | `with ... as session:` |
287
+ | Payment creation | `await client.create_payment_payload(...)` | `client.create_payment_payload(...)` |
288
+
289
+ ## pip Install Commands
290
+
291
+ ```bash
292
+ # httpx (async) + Algorand
293
+ pip install "x402-avm[httpx,avm]"
294
+
295
+ # requests (sync) + Algorand
296
+ pip install "x402-avm[requests,avm]"
297
+
298
+ # Both clients + Algorand
299
+ pip install "x402-avm[httpx,requests,avm]"
300
+
301
+ # Everything
302
+ pip install "x402-avm[all]"
303
+ ```
304
+
305
+ ## External Resources
306
+
307
+ - [x402-avm on PyPI](https://pypi.org/project/x402-avm/)
308
+ - [x402-avm Examples Repository](https://github.com/GoPlausible/x402-avm/tree/branch-v2-algorand-publish/examples/)
309
+ - [x402 Algorand Documentation](https://github.com/GoPlausible/.github/blob/main/profile/algorand-x402-documentation/)
310
+ - [httpx Documentation](https://www.python-httpx.org/)
311
+ - [requests Documentation](https://docs.python-requests.org/)
312
+ - [py-algorand-sdk Documentation](https://py-algorand-sdk.readthedocs.io/)
313
+ - [Coinbase x402 Specification](https://github.com/coinbase/x402)
@@ -0,0 +1,207 @@
1
+ # Creating x402 HTTP Clients in Python
2
+
3
+ Build Python HTTP clients with httpx (async) or requests (sync) that automatically detect 402 Payment Required responses, create Algorand USDC payment transactions, and retry with payment headers.
4
+
5
+ ## Prerequisites
6
+
7
+ Before using this skill, ensure:
8
+
9
+ 1. **Python 3.10+** is installed
10
+ 2. **An Algorand private key** -- Base64-encoded 64-byte key (set as `AVM_PRIVATE_KEY` env var)
11
+ 3. **USDC opt-in** -- The paying address must have opted into the USDC ASA on the target network
12
+ 4. **A payment-protected endpoint** -- A server running x402 middleware to test against
13
+
14
+ ## Core Workflow: Automatic 402 Handling
15
+
16
+ The x402 HTTP client wraps your HTTP library's transport layer. When a 402 response is received, it automatically creates a payment and retries.
17
+
18
+ ```
19
+ client.get("https://api.example.com/paid")
20
+ |
21
+ v
22
+ HTTP Transport sends request
23
+ |
24
+ v
25
+ Server returns 402 + PaymentRequirements
26
+ |
27
+ v
28
+ x402 Transport intercepts 402
29
+ |
30
+ v
31
+ ExactAvmScheme creates atomic transaction group
32
+ |
33
+ v
34
+ ClientAvmSigner signs payment transaction
35
+ |
36
+ v
37
+ Transport retries with PAYMENT-SIGNATURE header
38
+ |
39
+ v
40
+ Server verifies, settles, returns 200 + data
41
+ ```
42
+
43
+ ## How to Proceed
44
+
45
+ ### Step 1: Choose Async or Sync
46
+
47
+ | Library | Variant | x402 Client | Install |
48
+ |---------|---------|-------------|---------|
49
+ | httpx (async) | `x402HttpxClient` | `x402Client` | `pip install "x402-avm[httpx,avm]"` |
50
+ | requests (sync) | `x402_requests` | `x402ClientSync` | `pip install "x402-avm[requests,avm]"` |
51
+
52
+ ### Step 2: Implement ClientAvmSigner
53
+
54
+ Both async and sync clients need the same signer implementation:
55
+
56
+ ```python
57
+ import base64
58
+ from algosdk import encoding
59
+
60
+
61
+ class AlgorandSigner:
62
+ def __init__(self, secret_key: bytes, address: str):
63
+ self._secret_key = secret_key
64
+ self._address = address
65
+
66
+ @property
67
+ def address(self) -> str:
68
+ return self._address
69
+
70
+ def sign_transactions(
71
+ self,
72
+ unsigned_txns: list[bytes],
73
+ indexes_to_sign: list[int],
74
+ ) -> list[bytes | None]:
75
+ sk_b64 = base64.b64encode(self._secret_key).decode()
76
+ result: list[bytes | None] = []
77
+ for i, txn_bytes in enumerate(unsigned_txns):
78
+ if i in indexes_to_sign:
79
+ txn = encoding.msgpack_decode(
80
+ base64.b64encode(txn_bytes).decode()
81
+ )
82
+ signed = txn.sign(sk_b64)
83
+ result.append(
84
+ base64.b64decode(encoding.msgpack_encode(signed))
85
+ )
86
+ else:
87
+ result.append(None)
88
+ return result
89
+ ```
90
+
91
+ ### Step 3: Create Signer from Environment
92
+
93
+ ```python
94
+ import os
95
+ import base64
96
+ from algosdk import encoding
97
+
98
+ avm_private_key = os.environ["AVM_PRIVATE_KEY"]
99
+ secret_key = base64.b64decode(avm_private_key)
100
+ if len(secret_key) != 64:
101
+ raise ValueError("AVM_PRIVATE_KEY must be a Base64-encoded 64-byte key")
102
+
103
+ avm_address = encoding.encode_address(secret_key[32:])
104
+ signer = AlgorandSigner(secret_key, avm_address)
105
+ ```
106
+
107
+ ### Step 4: Register and Make Requests
108
+
109
+ **With httpx (async):**
110
+ ```python
111
+ import asyncio
112
+ from x402 import x402Client
113
+ from x402.http.clients.httpx import x402HttpxClient
114
+ from x402.mechanisms.avm.exact.register import register_exact_avm_client
115
+
116
+ async def main():
117
+ x402 = x402Client()
118
+ register_exact_avm_client(x402, signer)
119
+
120
+ async with x402HttpxClient(x402) as client:
121
+ response = await client.get("https://api.example.com/paid-resource")
122
+ print(response.status_code)
123
+ print(response.text)
124
+
125
+ asyncio.run(main())
126
+ ```
127
+
128
+ **With requests (sync):**
129
+ ```python
130
+ from x402 import x402ClientSync
131
+ from x402.http.clients.requests import x402_requests
132
+ from x402.mechanisms.avm.exact.register import register_exact_avm_client
133
+
134
+ x402 = x402ClientSync()
135
+ register_exact_avm_client(x402, signer)
136
+
137
+ with x402_requests(x402) as session:
138
+ response = session.get("https://api.example.com/paid-resource")
139
+ print(response.status_code)
140
+ print(response.text)
141
+ ```
142
+
143
+ ## Important Rules / Guidelines
144
+
145
+ 1. **httpx uses `x402Client` (async), requests uses `x402ClientSync` (sync)** -- mixing causes `TypeError`
146
+ 2. **Private key format** -- `AVM_PRIVATE_KEY` must be Base64-encoded 64 bytes (32-byte seed + 32-byte pubkey)
147
+ 3. **algosdk encoding boundaries** -- `msgpack_decode` expects base64 string, `msgpack_encode` returns base64 string, `sign()` expects base64 key
148
+ 4. **No infinite retry** -- The transport retries at most once; if the retry still returns 402, it passes through
149
+ 5. **Register before creating HTTP client** -- Call `register_exact_avm_client` before wrapping with httpx/requests
150
+ 6. **USDC opt-in required** -- The paying address must have opted into USDC on the target network
151
+
152
+ ## Alternative Client Creation Methods
153
+
154
+ ### `wrapHttpxWithPayment` (returns standard httpx.AsyncClient)
155
+
156
+ ```python
157
+ from x402.http.clients.httpx import wrapHttpxWithPayment
158
+
159
+ async with wrapHttpxWithPayment(x402, timeout=30.0) as client:
160
+ response = await client.get(url)
161
+ ```
162
+
163
+ ### `wrapRequestsWithPayment` (wraps existing session)
164
+
165
+ ```python
166
+ from x402.http.clients.requests import wrapRequestsWithPayment
167
+
168
+ session = requests.Session()
169
+ session.headers.update({"Authorization": "Bearer token"})
170
+ wrapRequestsWithPayment(session, x402)
171
+ response = session.get(url)
172
+ ```
173
+
174
+ ### Config-based setup
175
+
176
+ ```python
177
+ from x402 import x402ClientConfig, SchemeRegistration
178
+ from x402.mechanisms.avm.exact import ExactAvmClientScheme
179
+
180
+ config = x402ClientConfig(
181
+ schemes=[
182
+ SchemeRegistration(
183
+ network="algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
184
+ client=ExactAvmClientScheme(signer=my_signer),
185
+ ),
186
+ ],
187
+ )
188
+ ```
189
+
190
+ ## Common Errors / Troubleshooting
191
+
192
+ | Error | Cause | Solution |
193
+ |-------|-------|----------|
194
+ | `TypeError: x402HTTPAdapter requires sync client` | Used `x402Client` with requests | Use `x402ClientSync` for requests |
195
+ | `PaymentError: Failed to handle payment` | Payment creation or encoding failed | Check signer setup, private key, network registration |
196
+ | `ValueError: AVM_PRIVATE_KEY must be...` | Key is wrong length | Ensure key is Base64-encoded 64-byte key |
197
+ | `ImportError: AVM mechanism requires...` | `py-algorand-sdk` not installed | `pip install "x402-avm[avm]"` |
198
+ | `ImportError: requests client requires...` | `requests` not installed | `pip install "x402-avm[requests]"` |
199
+ | `ImportError: httpx client requires...` | `httpx` not installed | `pip install "x402-avm[httpx]"` |
200
+ | 402 returned after retry | Payment invalid or facilitator rejected | Check USDC balance, opt-in status, correct network |
201
+
202
+ ## References / Further Reading
203
+
204
+ - [create-python-x402-client-reference.md](./create-python-x402-client-reference.md) - Detailed API reference for httpx and requests
205
+ - [create-python-x402-client-examples.md](./create-python-x402-client-examples.md) - Complete code examples
206
+ - [x402-avm Examples Repository](https://github.com/GoPlausible/x402-avm/tree/branch-v2-algorand-publish/examples/)
207
+ - [x402 Algorand Documentation](https://github.com/GoPlausible/.github/blob/main/profile/algorand-x402-documentation/)