og-x402 0.0.1.dev1__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.
- og_x402-0.0.1.dev1/.gitignore +13 -0
- og_x402-0.0.1.dev1/PKG-INFO +317 -0
- og_x402-0.0.1.dev1/README.md +263 -0
- og_x402-0.0.1.dev1/__init__.py +229 -0
- og_x402-0.0.1.dev1/client.py +347 -0
- og_x402-0.0.1.dev1/client_base.py +410 -0
- og_x402-0.0.1.dev1/extensions/__init__.py +68 -0
- og_x402-0.0.1.dev1/extensions/bazaar/__init__.py +135 -0
- og_x402-0.0.1.dev1/extensions/bazaar/facilitator.py +322 -0
- og_x402-0.0.1.dev1/extensions/bazaar/facilitator_client.py +245 -0
- og_x402-0.0.1.dev1/extensions/bazaar/resource_service.py +271 -0
- og_x402-0.0.1.dev1/extensions/bazaar/server.py +114 -0
- og_x402-0.0.1.dev1/extensions/bazaar/types.py +158 -0
- og_x402-0.0.1.dev1/extensions/bazaar/v1/__init__.py +19 -0
- og_x402-0.0.1.dev1/extensions/bazaar/v1/facilitator.py +277 -0
- og_x402-0.0.1.dev1/facilitator.py +360 -0
- og_x402-0.0.1.dev1/facilitator_base.py +570 -0
- og_x402-0.0.1.dev1/http/__init__.py +128 -0
- og_x402-0.0.1.dev1/http/clients/__init__.py +68 -0
- og_x402-0.0.1.dev1/http/clients/httpx.py +493 -0
- og_x402-0.0.1.dev1/http/clients/requests.py +314 -0
- og_x402-0.0.1.dev1/http/constants.py +15 -0
- og_x402-0.0.1.dev1/http/facilitator_client.py +550 -0
- og_x402-0.0.1.dev1/http/facilitator_client_base.py +257 -0
- og_x402-0.0.1.dev1/http/middleware/__init__.py +72 -0
- og_x402-0.0.1.dev1/http/middleware/fastapi.py +462 -0
- og_x402-0.0.1.dev1/http/middleware/flask.py +2179 -0
- og_x402-0.0.1.dev1/http/paywall/__init__.py +439 -0
- og_x402-0.0.1.dev1/http/paywall/evm_paywall_template.py +2 -0
- og_x402-0.0.1.dev1/http/paywall/svm_paywall_template.py +2 -0
- og_x402-0.0.1.dev1/http/types.py +213 -0
- og_x402-0.0.1.dev1/http/utils.py +127 -0
- og_x402-0.0.1.dev1/http/x402_http_client.py +248 -0
- og_x402-0.0.1.dev1/http/x402_http_client_base.py +151 -0
- og_x402-0.0.1.dev1/http/x402_http_server.py +408 -0
- og_x402-0.0.1.dev1/http/x402_http_server_base.py +747 -0
- og_x402-0.0.1.dev1/interfaces.py +314 -0
- og_x402-0.0.1.dev1/mechanisms/evm/__init__.py +184 -0
- og_x402-0.0.1.dev1/mechanisms/evm/constants.py +377 -0
- og_x402-0.0.1.dev1/mechanisms/evm/eip712.py +269 -0
- og_x402-0.0.1.dev1/mechanisms/evm/erc6492.py +103 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/__init__.py +27 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/client.py +169 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/facilitator.py +407 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/permit2.py +189 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/register.py +139 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/server.py +160 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/v1/__init__.py +15 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/v1/client.py +131 -0
- og_x402-0.0.1.dev1/mechanisms/evm/exact/v1/facilitator.py +364 -0
- og_x402-0.0.1.dev1/mechanisms/evm/signer.py +178 -0
- og_x402-0.0.1.dev1/mechanisms/evm/signers.py +435 -0
- og_x402-0.0.1.dev1/mechanisms/evm/types.py +215 -0
- og_x402-0.0.1.dev1/mechanisms/evm/upto/__init__.py +23 -0
- og_x402-0.0.1.dev1/mechanisms/evm/upto/client.py +198 -0
- og_x402-0.0.1.dev1/mechanisms/evm/upto/facilitator.py +461 -0
- og_x402-0.0.1.dev1/mechanisms/evm/upto/register.py +110 -0
- og_x402-0.0.1.dev1/mechanisms/evm/upto/server.py +157 -0
- og_x402-0.0.1.dev1/mechanisms/evm/utils.py +293 -0
- og_x402-0.0.1.dev1/mechanisms/evm/verify.py +161 -0
- og_x402-0.0.1.dev1/mechanisms/svm/__init__.py +162 -0
- og_x402-0.0.1.dev1/mechanisms/svm/constants.py +138 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/__init__.py +23 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/client.py +219 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/facilitator.py +391 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/register.py +135 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/server.py +148 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/v1/__init__.py +13 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/v1/client.py +211 -0
- og_x402-0.0.1.dev1/mechanisms/svm/exact/v1/facilitator.py +367 -0
- og_x402-0.0.1.dev1/mechanisms/svm/signer.py +128 -0
- og_x402-0.0.1.dev1/mechanisms/svm/signers.py +371 -0
- og_x402-0.0.1.dev1/mechanisms/svm/types.py +55 -0
- og_x402-0.0.1.dev1/mechanisms/svm/utils.py +351 -0
- og_x402-0.0.1.dev1/py.typed +0 -0
- og_x402-0.0.1.dev1/pyproject.toml +180 -0
- og_x402-0.0.1.dev1/redis_session.py +258 -0
- og_x402-0.0.1.dev1/schemas/__init__.py +173 -0
- og_x402-0.0.1.dev1/schemas/base.py +49 -0
- og_x402-0.0.1.dev1/schemas/config.py +64 -0
- og_x402-0.0.1.dev1/schemas/errors.py +81 -0
- og_x402-0.0.1.dev1/schemas/extensions.py +32 -0
- og_x402-0.0.1.dev1/schemas/helpers.py +274 -0
- og_x402-0.0.1.dev1/schemas/hooks.py +213 -0
- og_x402-0.0.1.dev1/schemas/payments.py +95 -0
- og_x402-0.0.1.dev1/schemas/responses.py +98 -0
- og_x402-0.0.1.dev1/schemas/v1.py +96 -0
- og_x402-0.0.1.dev1/schemas/views.py +90 -0
- og_x402-0.0.1.dev1/server.py +607 -0
- og_x402-0.0.1.dev1/server_base.py +621 -0
- og_x402-0.0.1.dev1/session.py +262 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: og-x402
|
|
3
|
+
Version: 0.0.1.dev1
|
|
4
|
+
Summary: x402 Payment Protocol SDK for Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/coinbase/x402
|
|
6
|
+
Project-URL: Documentation, https://x402.org
|
|
7
|
+
Project-URL: Repository, https://github.com/coinbase/x402
|
|
8
|
+
Author: Coinbase
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: 402,http,payment,protocol,x402
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: pydantic>=2.0.0
|
|
22
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
23
|
+
Provides-Extra: all
|
|
24
|
+
Requires-Dist: x402[evm,extensions,fastapi,flask,httpx,redis,requests,svm]; extra == 'all'
|
|
25
|
+
Provides-Extra: clients
|
|
26
|
+
Requires-Dist: x402[httpx,requests]; extra == 'clients'
|
|
27
|
+
Provides-Extra: evm
|
|
28
|
+
Requires-Dist: eth-abi>=5.0.0; extra == 'evm'
|
|
29
|
+
Requires-Dist: eth-account>=0.12.0; extra == 'evm'
|
|
30
|
+
Requires-Dist: eth-keys>=0.5.0; extra == 'evm'
|
|
31
|
+
Requires-Dist: eth-utils>=4.0.0; extra == 'evm'
|
|
32
|
+
Requires-Dist: web3>=7.0.0; extra == 'evm'
|
|
33
|
+
Provides-Extra: extensions
|
|
34
|
+
Requires-Dist: jsonschema>=4.0.0; extra == 'extensions'
|
|
35
|
+
Provides-Extra: fastapi
|
|
36
|
+
Requires-Dist: fastapi[standard]>=0.115.0; extra == 'fastapi'
|
|
37
|
+
Requires-Dist: starlette>=0.27.0; extra == 'fastapi'
|
|
38
|
+
Provides-Extra: flask
|
|
39
|
+
Requires-Dist: flask>=3.0.0; extra == 'flask'
|
|
40
|
+
Provides-Extra: httpx
|
|
41
|
+
Requires-Dist: httpx>=0.28.1; extra == 'httpx'
|
|
42
|
+
Provides-Extra: mechanisms
|
|
43
|
+
Requires-Dist: x402[evm,svm]; extra == 'mechanisms'
|
|
44
|
+
Provides-Extra: redis
|
|
45
|
+
Requires-Dist: redis>=5.0.0; extra == 'redis'
|
|
46
|
+
Provides-Extra: requests
|
|
47
|
+
Requires-Dist: requests>=2.31.0; extra == 'requests'
|
|
48
|
+
Provides-Extra: servers
|
|
49
|
+
Requires-Dist: x402[fastapi,flask]; extra == 'servers'
|
|
50
|
+
Provides-Extra: svm
|
|
51
|
+
Requires-Dist: solana>=0.36.0; extra == 'svm'
|
|
52
|
+
Requires-Dist: solders>=0.27.0; extra == 'svm'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# x402 Python SDK
|
|
56
|
+
|
|
57
|
+
Core implementation of the x402 payment protocol. Provides transport-agnostic client, server, and facilitator components with both async and sync variants.
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
Install the core package with your preferred framework/client:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# HTTP clients (pick one)
|
|
65
|
+
uv add x402[httpx] # httpx client
|
|
66
|
+
uv add x402[requests] # requests client
|
|
67
|
+
|
|
68
|
+
# Server frameworks (pick one)
|
|
69
|
+
uv add x402[fastapi] # FastAPI middleware
|
|
70
|
+
uv add x402[flask] # Flask middleware
|
|
71
|
+
|
|
72
|
+
# Blockchain mechanisms (pick one or both)
|
|
73
|
+
uv add x402[evm] # EVM/Ethereum
|
|
74
|
+
uv add x402[svm] # Solana
|
|
75
|
+
|
|
76
|
+
# Multiple extras
|
|
77
|
+
uv add x402[fastapi,httpx,evm]
|
|
78
|
+
|
|
79
|
+
# Everything
|
|
80
|
+
uv add x402[all]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Quick Start
|
|
84
|
+
|
|
85
|
+
### Client (Async)
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from x402 import x402Client
|
|
89
|
+
from x402.mechanisms.evm.exact import ExactEvmScheme
|
|
90
|
+
|
|
91
|
+
client = x402Client()
|
|
92
|
+
client.register("eip155:*", ExactEvmScheme(signer=my_signer))
|
|
93
|
+
|
|
94
|
+
# Create payment from 402 response
|
|
95
|
+
payload = await client.create_payment_payload(payment_required)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Client (Sync)
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from x402 import x402ClientSync
|
|
102
|
+
from x402.mechanisms.evm.exact import ExactEvmScheme
|
|
103
|
+
|
|
104
|
+
client = x402ClientSync()
|
|
105
|
+
client.register("eip155:*", ExactEvmScheme(signer=my_signer))
|
|
106
|
+
|
|
107
|
+
payload = client.create_payment_payload(payment_required)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Server (Async)
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from x402 import x402ResourceServer, ResourceConfig
|
|
114
|
+
from x402.http import HTTPFacilitatorClient
|
|
115
|
+
from x402.mechanisms.evm.exact import ExactEvmServerScheme
|
|
116
|
+
|
|
117
|
+
facilitator = HTTPFacilitatorClient(url="https://x402.org/facilitator")
|
|
118
|
+
server = x402ResourceServer(facilitator)
|
|
119
|
+
server.register("eip155:*", ExactEvmServerScheme())
|
|
120
|
+
server.initialize()
|
|
121
|
+
|
|
122
|
+
# Build requirements
|
|
123
|
+
config = ResourceConfig(
|
|
124
|
+
scheme="exact",
|
|
125
|
+
network="eip155:8453",
|
|
126
|
+
pay_to="0x...",
|
|
127
|
+
price="$0.01",
|
|
128
|
+
)
|
|
129
|
+
requirements = server.build_payment_requirements(config)
|
|
130
|
+
|
|
131
|
+
# Verify payment
|
|
132
|
+
result = await server.verify_payment(payload, requirements[0])
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Server (Sync)
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from x402 import x402ResourceServerSync, ResourceConfig
|
|
139
|
+
from x402.http import HTTPFacilitatorClientSync
|
|
140
|
+
from x402.mechanisms.evm.exact import ExactEvmServerScheme
|
|
141
|
+
|
|
142
|
+
facilitator = HTTPFacilitatorClientSync(url="https://x402.org/facilitator")
|
|
143
|
+
server = x402ResourceServerSync(facilitator)
|
|
144
|
+
server.register("eip155:*", ExactEvmServerScheme())
|
|
145
|
+
server.initialize()
|
|
146
|
+
|
|
147
|
+
result = server.verify_payment(payload, requirements[0])
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Facilitator (Async)
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from x402 import x402Facilitator
|
|
154
|
+
from x402.mechanisms.evm.exact import ExactEvmFacilitatorScheme
|
|
155
|
+
|
|
156
|
+
facilitator = x402Facilitator()
|
|
157
|
+
facilitator.register(
|
|
158
|
+
["eip155:8453", "eip155:84532"],
|
|
159
|
+
ExactEvmFacilitatorScheme(wallet=wallet),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
result = await facilitator.verify(payload, requirements)
|
|
163
|
+
if result.is_valid:
|
|
164
|
+
settle_result = await facilitator.settle(payload, requirements)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Facilitator (Sync)
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from x402 import x402FacilitatorSync
|
|
171
|
+
from x402.mechanisms.evm.exact import ExactEvmFacilitatorScheme
|
|
172
|
+
|
|
173
|
+
facilitator = x402FacilitatorSync()
|
|
174
|
+
facilitator.register(
|
|
175
|
+
["eip155:8453", "eip155:84532"],
|
|
176
|
+
ExactEvmFacilitatorScheme(wallet=wallet),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
result = facilitator.verify(payload, requirements)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Async vs Sync
|
|
183
|
+
|
|
184
|
+
Each component has both async and sync variants:
|
|
185
|
+
|
|
186
|
+
| Async (default) | Sync |
|
|
187
|
+
|-----------------|------|
|
|
188
|
+
| `x402Client` | `x402ClientSync` |
|
|
189
|
+
| `x402ResourceServer` | `x402ResourceServerSync` |
|
|
190
|
+
| `x402Facilitator` | `x402FacilitatorSync` |
|
|
191
|
+
| `HTTPFacilitatorClient` | `HTTPFacilitatorClientSync` |
|
|
192
|
+
|
|
193
|
+
Async variants support both sync and async hooks (auto-detected). Sync variants only support sync hooks and raise `TypeError` if async hooks are registered.
|
|
194
|
+
|
|
195
|
+
### Framework Pairing
|
|
196
|
+
|
|
197
|
+
| Framework | HTTP Client | Server | Facilitator Client |
|
|
198
|
+
|-----------|-------------|--------|-------------------|
|
|
199
|
+
| FastAPI | httpx | `x402ResourceServer` | `HTTPFacilitatorClient` |
|
|
200
|
+
| Flask | requests | `x402ResourceServerSync` | `HTTPFacilitatorClientSync` |
|
|
201
|
+
|
|
202
|
+
Mismatched variants raise `TypeError` at runtime.
|
|
203
|
+
|
|
204
|
+
## Client Configuration
|
|
205
|
+
|
|
206
|
+
Use `from_config()` for declarative setup:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from x402 import x402Client, x402ClientConfig, SchemeRegistration
|
|
210
|
+
|
|
211
|
+
config = x402ClientConfig(
|
|
212
|
+
schemes=[
|
|
213
|
+
SchemeRegistration(network="eip155:*", client=ExactEvmScheme(signer)),
|
|
214
|
+
SchemeRegistration(network="solana:*", client=ExactSvmScheme(signer)),
|
|
215
|
+
],
|
|
216
|
+
policies=[prefer_network("eip155:8453")],
|
|
217
|
+
)
|
|
218
|
+
client = x402Client.from_config(config)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Policies
|
|
222
|
+
|
|
223
|
+
Filter or prioritize payment requirements:
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from x402 import prefer_network, prefer_scheme, max_amount
|
|
227
|
+
|
|
228
|
+
client.register_policy(prefer_network("eip155:8453"))
|
|
229
|
+
client.register_policy(prefer_scheme("exact"))
|
|
230
|
+
client.register_policy(max_amount(1_000_000)) # 1 USDC max
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Lifecycle Hooks
|
|
234
|
+
|
|
235
|
+
### Client Hooks
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
from x402 import AbortResult, RecoveredPayloadResult
|
|
239
|
+
|
|
240
|
+
def before_payment(ctx):
|
|
241
|
+
print(f"Creating payment for: {ctx.selected_requirements.network}")
|
|
242
|
+
# Return AbortResult(reason="...") to cancel
|
|
243
|
+
|
|
244
|
+
def after_payment(ctx):
|
|
245
|
+
print(f"Payment created: {ctx.payment_payload}")
|
|
246
|
+
|
|
247
|
+
def on_failure(ctx):
|
|
248
|
+
print(f"Payment failed: {ctx.error}")
|
|
249
|
+
# Return RecoveredPayloadResult(payload=...) to recover
|
|
250
|
+
|
|
251
|
+
client.on_before_payment_creation(before_payment)
|
|
252
|
+
client.on_after_payment_creation(after_payment)
|
|
253
|
+
client.on_payment_creation_failure(on_failure)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Server Hooks
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
server.on_before_verify(lambda ctx: print(f"Verifying: {ctx.payload}"))
|
|
260
|
+
server.on_after_verify(lambda ctx: print(f"Result: {ctx.result.is_valid}"))
|
|
261
|
+
server.on_verify_failure(lambda ctx: print(f"Failed: {ctx.error}"))
|
|
262
|
+
|
|
263
|
+
server.on_before_settle(lambda ctx: ...)
|
|
264
|
+
server.on_after_settle(lambda ctx: ...)
|
|
265
|
+
server.on_settle_failure(lambda ctx: ...)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Facilitator Hooks
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
facilitator.on_before_verify(...)
|
|
272
|
+
facilitator.on_after_verify(...)
|
|
273
|
+
facilitator.on_verify_failure(...)
|
|
274
|
+
facilitator.on_before_settle(...)
|
|
275
|
+
facilitator.on_after_settle(...)
|
|
276
|
+
facilitator.on_settle_failure(...)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Network Pattern Matching
|
|
280
|
+
|
|
281
|
+
Register handlers for network families using wildcards:
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
# All EVM networks
|
|
285
|
+
client.register("eip155:*", ExactEvmScheme(signer))
|
|
286
|
+
|
|
287
|
+
# Specific network (takes precedence)
|
|
288
|
+
client.register("eip155:8453", CustomScheme())
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## HTTP Headers
|
|
292
|
+
|
|
293
|
+
### V2 Protocol (Current)
|
|
294
|
+
|
|
295
|
+
| Header | Description |
|
|
296
|
+
|--------|-------------|
|
|
297
|
+
| `PAYMENT-SIGNATURE` | Base64-encoded payment payload |
|
|
298
|
+
| `PAYMENT-REQUIRED` | Base64-encoded payment requirements |
|
|
299
|
+
| `PAYMENT-RESPONSE` | Base64-encoded settlement response |
|
|
300
|
+
|
|
301
|
+
### V1 Protocol (Legacy)
|
|
302
|
+
|
|
303
|
+
| Header | Description |
|
|
304
|
+
|--------|-------------|
|
|
305
|
+
| `X-PAYMENT` | Base64-encoded payment payload |
|
|
306
|
+
| `X-PAYMENT-RESPONSE` | Base64-encoded settlement response |
|
|
307
|
+
|
|
308
|
+
## Related Modules
|
|
309
|
+
|
|
310
|
+
- `x402.http` - HTTP clients, middleware, and facilitator client
|
|
311
|
+
- `x402.mechanisms.evm` - EVM/Ethereum implementation
|
|
312
|
+
- `x402.mechanisms.svm` - Solana implementation
|
|
313
|
+
- `x402.extensions` - Protocol extensions (Bazaar discovery)
|
|
314
|
+
|
|
315
|
+
## Examples
|
|
316
|
+
|
|
317
|
+
See [examples/python](https://github.com/coinbase/x402/tree/main/examples/python).
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# x402 Python SDK
|
|
2
|
+
|
|
3
|
+
Core implementation of the x402 payment protocol. Provides transport-agnostic client, server, and facilitator components with both async and sync variants.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install the core package with your preferred framework/client:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# HTTP clients (pick one)
|
|
11
|
+
uv add x402[httpx] # httpx client
|
|
12
|
+
uv add x402[requests] # requests client
|
|
13
|
+
|
|
14
|
+
# Server frameworks (pick one)
|
|
15
|
+
uv add x402[fastapi] # FastAPI middleware
|
|
16
|
+
uv add x402[flask] # Flask middleware
|
|
17
|
+
|
|
18
|
+
# Blockchain mechanisms (pick one or both)
|
|
19
|
+
uv add x402[evm] # EVM/Ethereum
|
|
20
|
+
uv add x402[svm] # Solana
|
|
21
|
+
|
|
22
|
+
# Multiple extras
|
|
23
|
+
uv add x402[fastapi,httpx,evm]
|
|
24
|
+
|
|
25
|
+
# Everything
|
|
26
|
+
uv add x402[all]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### Client (Async)
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from x402 import x402Client
|
|
35
|
+
from x402.mechanisms.evm.exact import ExactEvmScheme
|
|
36
|
+
|
|
37
|
+
client = x402Client()
|
|
38
|
+
client.register("eip155:*", ExactEvmScheme(signer=my_signer))
|
|
39
|
+
|
|
40
|
+
# Create payment from 402 response
|
|
41
|
+
payload = await client.create_payment_payload(payment_required)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Client (Sync)
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from x402 import x402ClientSync
|
|
48
|
+
from x402.mechanisms.evm.exact import ExactEvmScheme
|
|
49
|
+
|
|
50
|
+
client = x402ClientSync()
|
|
51
|
+
client.register("eip155:*", ExactEvmScheme(signer=my_signer))
|
|
52
|
+
|
|
53
|
+
payload = client.create_payment_payload(payment_required)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Server (Async)
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from x402 import x402ResourceServer, ResourceConfig
|
|
60
|
+
from x402.http import HTTPFacilitatorClient
|
|
61
|
+
from x402.mechanisms.evm.exact import ExactEvmServerScheme
|
|
62
|
+
|
|
63
|
+
facilitator = HTTPFacilitatorClient(url="https://x402.org/facilitator")
|
|
64
|
+
server = x402ResourceServer(facilitator)
|
|
65
|
+
server.register("eip155:*", ExactEvmServerScheme())
|
|
66
|
+
server.initialize()
|
|
67
|
+
|
|
68
|
+
# Build requirements
|
|
69
|
+
config = ResourceConfig(
|
|
70
|
+
scheme="exact",
|
|
71
|
+
network="eip155:8453",
|
|
72
|
+
pay_to="0x...",
|
|
73
|
+
price="$0.01",
|
|
74
|
+
)
|
|
75
|
+
requirements = server.build_payment_requirements(config)
|
|
76
|
+
|
|
77
|
+
# Verify payment
|
|
78
|
+
result = await server.verify_payment(payload, requirements[0])
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Server (Sync)
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from x402 import x402ResourceServerSync, ResourceConfig
|
|
85
|
+
from x402.http import HTTPFacilitatorClientSync
|
|
86
|
+
from x402.mechanisms.evm.exact import ExactEvmServerScheme
|
|
87
|
+
|
|
88
|
+
facilitator = HTTPFacilitatorClientSync(url="https://x402.org/facilitator")
|
|
89
|
+
server = x402ResourceServerSync(facilitator)
|
|
90
|
+
server.register("eip155:*", ExactEvmServerScheme())
|
|
91
|
+
server.initialize()
|
|
92
|
+
|
|
93
|
+
result = server.verify_payment(payload, requirements[0])
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Facilitator (Async)
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from x402 import x402Facilitator
|
|
100
|
+
from x402.mechanisms.evm.exact import ExactEvmFacilitatorScheme
|
|
101
|
+
|
|
102
|
+
facilitator = x402Facilitator()
|
|
103
|
+
facilitator.register(
|
|
104
|
+
["eip155:8453", "eip155:84532"],
|
|
105
|
+
ExactEvmFacilitatorScheme(wallet=wallet),
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
result = await facilitator.verify(payload, requirements)
|
|
109
|
+
if result.is_valid:
|
|
110
|
+
settle_result = await facilitator.settle(payload, requirements)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Facilitator (Sync)
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from x402 import x402FacilitatorSync
|
|
117
|
+
from x402.mechanisms.evm.exact import ExactEvmFacilitatorScheme
|
|
118
|
+
|
|
119
|
+
facilitator = x402FacilitatorSync()
|
|
120
|
+
facilitator.register(
|
|
121
|
+
["eip155:8453", "eip155:84532"],
|
|
122
|
+
ExactEvmFacilitatorScheme(wallet=wallet),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
result = facilitator.verify(payload, requirements)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Async vs Sync
|
|
129
|
+
|
|
130
|
+
Each component has both async and sync variants:
|
|
131
|
+
|
|
132
|
+
| Async (default) | Sync |
|
|
133
|
+
|-----------------|------|
|
|
134
|
+
| `x402Client` | `x402ClientSync` |
|
|
135
|
+
| `x402ResourceServer` | `x402ResourceServerSync` |
|
|
136
|
+
| `x402Facilitator` | `x402FacilitatorSync` |
|
|
137
|
+
| `HTTPFacilitatorClient` | `HTTPFacilitatorClientSync` |
|
|
138
|
+
|
|
139
|
+
Async variants support both sync and async hooks (auto-detected). Sync variants only support sync hooks and raise `TypeError` if async hooks are registered.
|
|
140
|
+
|
|
141
|
+
### Framework Pairing
|
|
142
|
+
|
|
143
|
+
| Framework | HTTP Client | Server | Facilitator Client |
|
|
144
|
+
|-----------|-------------|--------|-------------------|
|
|
145
|
+
| FastAPI | httpx | `x402ResourceServer` | `HTTPFacilitatorClient` |
|
|
146
|
+
| Flask | requests | `x402ResourceServerSync` | `HTTPFacilitatorClientSync` |
|
|
147
|
+
|
|
148
|
+
Mismatched variants raise `TypeError` at runtime.
|
|
149
|
+
|
|
150
|
+
## Client Configuration
|
|
151
|
+
|
|
152
|
+
Use `from_config()` for declarative setup:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from x402 import x402Client, x402ClientConfig, SchemeRegistration
|
|
156
|
+
|
|
157
|
+
config = x402ClientConfig(
|
|
158
|
+
schemes=[
|
|
159
|
+
SchemeRegistration(network="eip155:*", client=ExactEvmScheme(signer)),
|
|
160
|
+
SchemeRegistration(network="solana:*", client=ExactSvmScheme(signer)),
|
|
161
|
+
],
|
|
162
|
+
policies=[prefer_network("eip155:8453")],
|
|
163
|
+
)
|
|
164
|
+
client = x402Client.from_config(config)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Policies
|
|
168
|
+
|
|
169
|
+
Filter or prioritize payment requirements:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from x402 import prefer_network, prefer_scheme, max_amount
|
|
173
|
+
|
|
174
|
+
client.register_policy(prefer_network("eip155:8453"))
|
|
175
|
+
client.register_policy(prefer_scheme("exact"))
|
|
176
|
+
client.register_policy(max_amount(1_000_000)) # 1 USDC max
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Lifecycle Hooks
|
|
180
|
+
|
|
181
|
+
### Client Hooks
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from x402 import AbortResult, RecoveredPayloadResult
|
|
185
|
+
|
|
186
|
+
def before_payment(ctx):
|
|
187
|
+
print(f"Creating payment for: {ctx.selected_requirements.network}")
|
|
188
|
+
# Return AbortResult(reason="...") to cancel
|
|
189
|
+
|
|
190
|
+
def after_payment(ctx):
|
|
191
|
+
print(f"Payment created: {ctx.payment_payload}")
|
|
192
|
+
|
|
193
|
+
def on_failure(ctx):
|
|
194
|
+
print(f"Payment failed: {ctx.error}")
|
|
195
|
+
# Return RecoveredPayloadResult(payload=...) to recover
|
|
196
|
+
|
|
197
|
+
client.on_before_payment_creation(before_payment)
|
|
198
|
+
client.on_after_payment_creation(after_payment)
|
|
199
|
+
client.on_payment_creation_failure(on_failure)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Server Hooks
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
server.on_before_verify(lambda ctx: print(f"Verifying: {ctx.payload}"))
|
|
206
|
+
server.on_after_verify(lambda ctx: print(f"Result: {ctx.result.is_valid}"))
|
|
207
|
+
server.on_verify_failure(lambda ctx: print(f"Failed: {ctx.error}"))
|
|
208
|
+
|
|
209
|
+
server.on_before_settle(lambda ctx: ...)
|
|
210
|
+
server.on_after_settle(lambda ctx: ...)
|
|
211
|
+
server.on_settle_failure(lambda ctx: ...)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Facilitator Hooks
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
facilitator.on_before_verify(...)
|
|
218
|
+
facilitator.on_after_verify(...)
|
|
219
|
+
facilitator.on_verify_failure(...)
|
|
220
|
+
facilitator.on_before_settle(...)
|
|
221
|
+
facilitator.on_after_settle(...)
|
|
222
|
+
facilitator.on_settle_failure(...)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Network Pattern Matching
|
|
226
|
+
|
|
227
|
+
Register handlers for network families using wildcards:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
# All EVM networks
|
|
231
|
+
client.register("eip155:*", ExactEvmScheme(signer))
|
|
232
|
+
|
|
233
|
+
# Specific network (takes precedence)
|
|
234
|
+
client.register("eip155:8453", CustomScheme())
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## HTTP Headers
|
|
238
|
+
|
|
239
|
+
### V2 Protocol (Current)
|
|
240
|
+
|
|
241
|
+
| Header | Description |
|
|
242
|
+
|--------|-------------|
|
|
243
|
+
| `PAYMENT-SIGNATURE` | Base64-encoded payment payload |
|
|
244
|
+
| `PAYMENT-REQUIRED` | Base64-encoded payment requirements |
|
|
245
|
+
| `PAYMENT-RESPONSE` | Base64-encoded settlement response |
|
|
246
|
+
|
|
247
|
+
### V1 Protocol (Legacy)
|
|
248
|
+
|
|
249
|
+
| Header | Description |
|
|
250
|
+
|--------|-------------|
|
|
251
|
+
| `X-PAYMENT` | Base64-encoded payment payload |
|
|
252
|
+
| `X-PAYMENT-RESPONSE` | Base64-encoded settlement response |
|
|
253
|
+
|
|
254
|
+
## Related Modules
|
|
255
|
+
|
|
256
|
+
- `x402.http` - HTTP clients, middleware, and facilitator client
|
|
257
|
+
- `x402.mechanisms.evm` - EVM/Ethereum implementation
|
|
258
|
+
- `x402.mechanisms.svm` - Solana implementation
|
|
259
|
+
- `x402.extensions` - Protocol extensions (Bazaar discovery)
|
|
260
|
+
|
|
261
|
+
## Examples
|
|
262
|
+
|
|
263
|
+
See [examples/python](https://github.com/coinbase/x402/tree/main/examples/python).
|