clawfetch 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.
- clawfetch-0.1.0/PKG-INFO +268 -0
- clawfetch-0.1.0/README.md +244 -0
- clawfetch-0.1.0/clawfetch/__init__.py +17 -0
- clawfetch-0.1.0/clawfetch/async_client.py +451 -0
- clawfetch-0.1.0/clawfetch/client.py +478 -0
- clawfetch-0.1.0/clawfetch/errors.py +49 -0
- clawfetch-0.1.0/clawfetch.egg-info/PKG-INFO +268 -0
- clawfetch-0.1.0/clawfetch.egg-info/SOURCES.txt +14 -0
- clawfetch-0.1.0/clawfetch.egg-info/dependency_links.txt +1 -0
- clawfetch-0.1.0/clawfetch.egg-info/requires.txt +8 -0
- clawfetch-0.1.0/clawfetch.egg-info/top_level.txt +1 -0
- clawfetch-0.1.0/pyproject.toml +39 -0
- clawfetch-0.1.0/setup.cfg +4 -0
- clawfetch-0.1.0/tests/test_async_client.py +622 -0
- clawfetch-0.1.0/tests/test_client.py +749 -0
- clawfetch-0.1.0/tests/test_retry.py +388 -0
clawfetch-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clawfetch
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for ClawFetch — Web Intelligence API for AI Agents (x402-native)
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://api.clawfetch.ai
|
|
7
|
+
Project-URL: Repository, https://github.com/clawfetch/sdk-python
|
|
8
|
+
Keywords: clawfetch,x402,web-intelligence,ai-agents,crypto,usdc,base
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: httpx>=0.25.0
|
|
18
|
+
Requires-Dist: eth-account>=0.13.0
|
|
19
|
+
Requires-Dist: eth-abi>=5.0.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=9.0; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-mock>=3.15; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
|
|
24
|
+
|
|
25
|
+
# clawfetch
|
|
26
|
+
|
|
27
|
+
Python SDK for [ClawFetch](https://api.clawfetch.ai) — Web Intelligence API for AI Agents.
|
|
28
|
+
|
|
29
|
+
Pay-per-request via [x402](https://x402.org) (gasless USDC on Base). No API keys, no subscriptions.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install clawfetch
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
### Sync
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from clawfetch import ClawFetch
|
|
43
|
+
|
|
44
|
+
with ClawFetch(private_key="0x...") as cf:
|
|
45
|
+
# Fetch any URL as clean markdown ($0.001)
|
|
46
|
+
page = cf.fetch("https://example.com")
|
|
47
|
+
|
|
48
|
+
# Extract structured data ($0.003)
|
|
49
|
+
btc = cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
50
|
+
print(btc["data"])
|
|
51
|
+
|
|
52
|
+
# Multi-source research ($0.01)
|
|
53
|
+
report = cf.research("latest AI agent frameworks")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Async
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
from clawfetch import AsyncClawFetch
|
|
61
|
+
|
|
62
|
+
async def main():
|
|
63
|
+
async with AsyncClawFetch(private_key="0x...") as cf:
|
|
64
|
+
page = await cf.fetch("https://example.com")
|
|
65
|
+
btc = await cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
66
|
+
report = await cf.research("latest AI agent frameworks")
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Both clients have identical APIs — all 7 endpoints, full x402 payment flow, retry with exponential backoff, and typed error hierarchy.
|
|
72
|
+
|
|
73
|
+
## API
|
|
74
|
+
|
|
75
|
+
| Method | Price | Description |
|
|
76
|
+
|--------|-------|-------------|
|
|
77
|
+
| `fetch(url)` | $0.001 | URL → clean markdown |
|
|
78
|
+
| `render(url)` | $0.002 | JS-rendered page → markdown |
|
|
79
|
+
| `extract(url)` | $0.003 | Structured data from 17+ sites |
|
|
80
|
+
| `research(topic)` | $0.010 | Multi-source topic research |
|
|
81
|
+
| `domains_check(domains)` | $0.002 | Domain availability check |
|
|
82
|
+
| `domains_suggest(query)` | $0.002 | Domain name suggestions |
|
|
83
|
+
| `extractors()` | $0.001 | List available extractors |
|
|
84
|
+
| `health()` | Free | API status check |
|
|
85
|
+
|
|
86
|
+
## Error Handling
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from clawfetch import (
|
|
90
|
+
ClawFetch,
|
|
91
|
+
ClawFetchError, # Base class
|
|
92
|
+
PaymentError, # 402 — insufficient USDC
|
|
93
|
+
NetworkError, # Connection/timeout failures
|
|
94
|
+
RateLimitError, # 429 — includes retry_after_ms
|
|
95
|
+
ApiError, # Other 4xx/5xx errors
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Configuration
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from clawfetch import ClawFetch, RetryOptions
|
|
103
|
+
|
|
104
|
+
cf = ClawFetch(
|
|
105
|
+
private_key="0x...",
|
|
106
|
+
base_url="https://api.clawfetch.ai", # default
|
|
107
|
+
timeout=30.0, # seconds
|
|
108
|
+
retry=RetryOptions(
|
|
109
|
+
max_retries=3,
|
|
110
|
+
initial_delay_ms=500,
|
|
111
|
+
max_delay_ms=10000,
|
|
112
|
+
backoff_multiplier=2.0,
|
|
113
|
+
),
|
|
114
|
+
debug=False,
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Requirements
|
|
119
|
+
|
|
120
|
+
- Python 3.9+
|
|
121
|
+
- A wallet with USDC on Base (even $1 gives you 1,000+ requests)
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
# Original README below
|
|
130
|
+
|
|
131
|
+
Python SDK for [ClawFetch](https://api.clawfetch.ai) — Web Intelligence API for AI Agents.
|
|
132
|
+
|
|
133
|
+
Pay-per-request via [x402](https://x402.org) (gasless USDC on Base). No API keys, no subscriptions.
|
|
134
|
+
|
|
135
|
+
## Install
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pip install clawfetch
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Quick Start
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from clawfetch import ClawFetch
|
|
145
|
+
|
|
146
|
+
cf = ClawFetch(private_key="0x...")
|
|
147
|
+
|
|
148
|
+
# Fetch any URL as clean markdown ($0.001)
|
|
149
|
+
page = cf.fetch("https://example.com")
|
|
150
|
+
|
|
151
|
+
# Extract structured data ($0.003)
|
|
152
|
+
btc = cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
153
|
+
print(btc["data"]) # {'name': 'Bitcoin', 'price': 98432.12, ...}
|
|
154
|
+
|
|
155
|
+
# JS-rendered pages ($0.002)
|
|
156
|
+
rendered = cf.render("https://app.uniswap.org")
|
|
157
|
+
|
|
158
|
+
# Multi-source research ($0.01)
|
|
159
|
+
report = cf.research("latest AI agent frameworks")
|
|
160
|
+
|
|
161
|
+
# Domain availability ($0.002)
|
|
162
|
+
domains = cf.domains_check(["coolstartup.com", "coolstartup.ai"])
|
|
163
|
+
|
|
164
|
+
# List extractors ($0.001)
|
|
165
|
+
extractors = cf.extractors()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Configuration
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from clawfetch import ClawFetch, RetryOptions
|
|
172
|
+
|
|
173
|
+
cf = ClawFetch(
|
|
174
|
+
private_key="0x...",
|
|
175
|
+
base_url="https://api.clawfetch.ai", # default
|
|
176
|
+
timeout=30.0, # request timeout in seconds
|
|
177
|
+
retry=RetryOptions( # or False to disable retries
|
|
178
|
+
max_retries=3,
|
|
179
|
+
initial_delay_ms=500,
|
|
180
|
+
max_delay_ms=10_000,
|
|
181
|
+
backoff_multiplier=2.0,
|
|
182
|
+
),
|
|
183
|
+
debug=False, # enable debug logging
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Error Handling
|
|
188
|
+
|
|
189
|
+
All errors extend `ClawFetchError` for easy catching:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from clawfetch import ClawFetch, ClawFetchError, PaymentError, NetworkError, RateLimitError, ApiError
|
|
193
|
+
|
|
194
|
+
cf = ClawFetch(private_key="0x...")
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
result = cf.fetch("https://example.com")
|
|
198
|
+
except PaymentError as e:
|
|
199
|
+
print(f"Payment failed ({e.status_code}): {e}")
|
|
200
|
+
except RateLimitError as e:
|
|
201
|
+
print(f"Rate limited, retry after {e.retry_after_ms}ms")
|
|
202
|
+
except NetworkError as e:
|
|
203
|
+
print(f"Network error: {e}")
|
|
204
|
+
except ApiError as e:
|
|
205
|
+
print(f"API error {e.status_code}: {e}")
|
|
206
|
+
except ClawFetchError as e:
|
|
207
|
+
print(f"ClawFetch error: {e}")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
| Error | Status | Retried |
|
|
211
|
+
|-------|--------|---------|
|
|
212
|
+
| `PaymentError` | 402 | No |
|
|
213
|
+
| `RateLimitError` | 429 | Yes (with Retry-After) |
|
|
214
|
+
| `ApiError` | 400, 401, 404 | No |
|
|
215
|
+
| `ApiError` | 500, 502, 503, 504 | Yes |
|
|
216
|
+
| `NetworkError` | Connection/timeout | Yes |
|
|
217
|
+
|
|
218
|
+
## Retry Behavior
|
|
219
|
+
|
|
220
|
+
By default, retries are enabled with exponential backoff + jitter:
|
|
221
|
+
|
|
222
|
+
| Attempt | Delay |
|
|
223
|
+
|---------|-------|
|
|
224
|
+
| 1st retry | ~500ms |
|
|
225
|
+
| 2nd retry | ~1,000ms |
|
|
226
|
+
| 3rd retry | ~2,000ms |
|
|
227
|
+
|
|
228
|
+
Respects `Retry-After` headers on 429 responses. Non-retryable errors (400, 401, 402, 404) fail immediately.
|
|
229
|
+
|
|
230
|
+
Disable retries:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
cf = ClawFetch(private_key="0x...", retry=False)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## How It Works
|
|
237
|
+
|
|
238
|
+
1. SDK makes a request to ClawFetch
|
|
239
|
+
2. Server returns `402 Payment Required` with USDC amount
|
|
240
|
+
3. SDK auto-signs an EIP-3009 gasless USDC transfer on Base
|
|
241
|
+
4. Request is retried with payment header
|
|
242
|
+
5. You get structured data back
|
|
243
|
+
|
|
244
|
+
No gas fees. No API keys. Just USDC on Base.
|
|
245
|
+
|
|
246
|
+
## Context Manager
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
with ClawFetch(private_key="0x...") as cf:
|
|
250
|
+
data = cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
251
|
+
# Client is automatically closed
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Requirements
|
|
255
|
+
|
|
256
|
+
- Python 3.9+
|
|
257
|
+
- A wallet with USDC on Base (even $1 gives you 1,000+ requests)
|
|
258
|
+
|
|
259
|
+
## Development
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
pip install -e ".[dev]"
|
|
263
|
+
pytest tests/ -v
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
MIT
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# clawfetch
|
|
2
|
+
|
|
3
|
+
Python SDK for [ClawFetch](https://api.clawfetch.ai) — Web Intelligence API for AI Agents.
|
|
4
|
+
|
|
5
|
+
Pay-per-request via [x402](https://x402.org) (gasless USDC on Base). No API keys, no subscriptions.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install clawfetch
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Sync
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from clawfetch import ClawFetch
|
|
19
|
+
|
|
20
|
+
with ClawFetch(private_key="0x...") as cf:
|
|
21
|
+
# Fetch any URL as clean markdown ($0.001)
|
|
22
|
+
page = cf.fetch("https://example.com")
|
|
23
|
+
|
|
24
|
+
# Extract structured data ($0.003)
|
|
25
|
+
btc = cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
26
|
+
print(btc["data"])
|
|
27
|
+
|
|
28
|
+
# Multi-source research ($0.01)
|
|
29
|
+
report = cf.research("latest AI agent frameworks")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Async
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import asyncio
|
|
36
|
+
from clawfetch import AsyncClawFetch
|
|
37
|
+
|
|
38
|
+
async def main():
|
|
39
|
+
async with AsyncClawFetch(private_key="0x...") as cf:
|
|
40
|
+
page = await cf.fetch("https://example.com")
|
|
41
|
+
btc = await cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
42
|
+
report = await cf.research("latest AI agent frameworks")
|
|
43
|
+
|
|
44
|
+
asyncio.run(main())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Both clients have identical APIs — all 7 endpoints, full x402 payment flow, retry with exponential backoff, and typed error hierarchy.
|
|
48
|
+
|
|
49
|
+
## API
|
|
50
|
+
|
|
51
|
+
| Method | Price | Description |
|
|
52
|
+
|--------|-------|-------------|
|
|
53
|
+
| `fetch(url)` | $0.001 | URL → clean markdown |
|
|
54
|
+
| `render(url)` | $0.002 | JS-rendered page → markdown |
|
|
55
|
+
| `extract(url)` | $0.003 | Structured data from 17+ sites |
|
|
56
|
+
| `research(topic)` | $0.010 | Multi-source topic research |
|
|
57
|
+
| `domains_check(domains)` | $0.002 | Domain availability check |
|
|
58
|
+
| `domains_suggest(query)` | $0.002 | Domain name suggestions |
|
|
59
|
+
| `extractors()` | $0.001 | List available extractors |
|
|
60
|
+
| `health()` | Free | API status check |
|
|
61
|
+
|
|
62
|
+
## Error Handling
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from clawfetch import (
|
|
66
|
+
ClawFetch,
|
|
67
|
+
ClawFetchError, # Base class
|
|
68
|
+
PaymentError, # 402 — insufficient USDC
|
|
69
|
+
NetworkError, # Connection/timeout failures
|
|
70
|
+
RateLimitError, # 429 — includes retry_after_ms
|
|
71
|
+
ApiError, # Other 4xx/5xx errors
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from clawfetch import ClawFetch, RetryOptions
|
|
79
|
+
|
|
80
|
+
cf = ClawFetch(
|
|
81
|
+
private_key="0x...",
|
|
82
|
+
base_url="https://api.clawfetch.ai", # default
|
|
83
|
+
timeout=30.0, # seconds
|
|
84
|
+
retry=RetryOptions(
|
|
85
|
+
max_retries=3,
|
|
86
|
+
initial_delay_ms=500,
|
|
87
|
+
max_delay_ms=10000,
|
|
88
|
+
backoff_multiplier=2.0,
|
|
89
|
+
),
|
|
90
|
+
debug=False,
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Requirements
|
|
95
|
+
|
|
96
|
+
- Python 3.9+
|
|
97
|
+
- A wallet with USDC on Base (even $1 gives you 1,000+ requests)
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
# Original README below
|
|
106
|
+
|
|
107
|
+
Python SDK for [ClawFetch](https://api.clawfetch.ai) — Web Intelligence API for AI Agents.
|
|
108
|
+
|
|
109
|
+
Pay-per-request via [x402](https://x402.org) (gasless USDC on Base). No API keys, no subscriptions.
|
|
110
|
+
|
|
111
|
+
## Install
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pip install clawfetch
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Quick Start
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from clawfetch import ClawFetch
|
|
121
|
+
|
|
122
|
+
cf = ClawFetch(private_key="0x...")
|
|
123
|
+
|
|
124
|
+
# Fetch any URL as clean markdown ($0.001)
|
|
125
|
+
page = cf.fetch("https://example.com")
|
|
126
|
+
|
|
127
|
+
# Extract structured data ($0.003)
|
|
128
|
+
btc = cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
129
|
+
print(btc["data"]) # {'name': 'Bitcoin', 'price': 98432.12, ...}
|
|
130
|
+
|
|
131
|
+
# JS-rendered pages ($0.002)
|
|
132
|
+
rendered = cf.render("https://app.uniswap.org")
|
|
133
|
+
|
|
134
|
+
# Multi-source research ($0.01)
|
|
135
|
+
report = cf.research("latest AI agent frameworks")
|
|
136
|
+
|
|
137
|
+
# Domain availability ($0.002)
|
|
138
|
+
domains = cf.domains_check(["coolstartup.com", "coolstartup.ai"])
|
|
139
|
+
|
|
140
|
+
# List extractors ($0.001)
|
|
141
|
+
extractors = cf.extractors()
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Configuration
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from clawfetch import ClawFetch, RetryOptions
|
|
148
|
+
|
|
149
|
+
cf = ClawFetch(
|
|
150
|
+
private_key="0x...",
|
|
151
|
+
base_url="https://api.clawfetch.ai", # default
|
|
152
|
+
timeout=30.0, # request timeout in seconds
|
|
153
|
+
retry=RetryOptions( # or False to disable retries
|
|
154
|
+
max_retries=3,
|
|
155
|
+
initial_delay_ms=500,
|
|
156
|
+
max_delay_ms=10_000,
|
|
157
|
+
backoff_multiplier=2.0,
|
|
158
|
+
),
|
|
159
|
+
debug=False, # enable debug logging
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Error Handling
|
|
164
|
+
|
|
165
|
+
All errors extend `ClawFetchError` for easy catching:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from clawfetch import ClawFetch, ClawFetchError, PaymentError, NetworkError, RateLimitError, ApiError
|
|
169
|
+
|
|
170
|
+
cf = ClawFetch(private_key="0x...")
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
result = cf.fetch("https://example.com")
|
|
174
|
+
except PaymentError as e:
|
|
175
|
+
print(f"Payment failed ({e.status_code}): {e}")
|
|
176
|
+
except RateLimitError as e:
|
|
177
|
+
print(f"Rate limited, retry after {e.retry_after_ms}ms")
|
|
178
|
+
except NetworkError as e:
|
|
179
|
+
print(f"Network error: {e}")
|
|
180
|
+
except ApiError as e:
|
|
181
|
+
print(f"API error {e.status_code}: {e}")
|
|
182
|
+
except ClawFetchError as e:
|
|
183
|
+
print(f"ClawFetch error: {e}")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| Error | Status | Retried |
|
|
187
|
+
|-------|--------|---------|
|
|
188
|
+
| `PaymentError` | 402 | No |
|
|
189
|
+
| `RateLimitError` | 429 | Yes (with Retry-After) |
|
|
190
|
+
| `ApiError` | 400, 401, 404 | No |
|
|
191
|
+
| `ApiError` | 500, 502, 503, 504 | Yes |
|
|
192
|
+
| `NetworkError` | Connection/timeout | Yes |
|
|
193
|
+
|
|
194
|
+
## Retry Behavior
|
|
195
|
+
|
|
196
|
+
By default, retries are enabled with exponential backoff + jitter:
|
|
197
|
+
|
|
198
|
+
| Attempt | Delay |
|
|
199
|
+
|---------|-------|
|
|
200
|
+
| 1st retry | ~500ms |
|
|
201
|
+
| 2nd retry | ~1,000ms |
|
|
202
|
+
| 3rd retry | ~2,000ms |
|
|
203
|
+
|
|
204
|
+
Respects `Retry-After` headers on 429 responses. Non-retryable errors (400, 401, 402, 404) fail immediately.
|
|
205
|
+
|
|
206
|
+
Disable retries:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
cf = ClawFetch(private_key="0x...", retry=False)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## How It Works
|
|
213
|
+
|
|
214
|
+
1. SDK makes a request to ClawFetch
|
|
215
|
+
2. Server returns `402 Payment Required` with USDC amount
|
|
216
|
+
3. SDK auto-signs an EIP-3009 gasless USDC transfer on Base
|
|
217
|
+
4. Request is retried with payment header
|
|
218
|
+
5. You get structured data back
|
|
219
|
+
|
|
220
|
+
No gas fees. No API keys. Just USDC on Base.
|
|
221
|
+
|
|
222
|
+
## Context Manager
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
with ClawFetch(private_key="0x...") as cf:
|
|
226
|
+
data = cf.extract("https://coingecko.com/en/coins/bitcoin")
|
|
227
|
+
# Client is automatically closed
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Requirements
|
|
231
|
+
|
|
232
|
+
- Python 3.9+
|
|
233
|
+
- A wallet with USDC on Base (even $1 gives you 1,000+ requests)
|
|
234
|
+
|
|
235
|
+
## Development
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
pip install -e ".[dev]"
|
|
239
|
+
pytest tests/ -v
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""ClawFetch — Web Intelligence API for AI Agents (x402-native)"""
|
|
2
|
+
|
|
3
|
+
from .client import ClawFetch, RetryOptions
|
|
4
|
+
from .async_client import AsyncClawFetch
|
|
5
|
+
from .errors import ApiError, ClawFetchError, NetworkError, PaymentError, RateLimitError
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"ClawFetch",
|
|
9
|
+
"AsyncClawFetch",
|
|
10
|
+
"RetryOptions",
|
|
11
|
+
"ClawFetchError",
|
|
12
|
+
"PaymentError",
|
|
13
|
+
"NetworkError",
|
|
14
|
+
"RateLimitError",
|
|
15
|
+
"ApiError",
|
|
16
|
+
]
|
|
17
|
+
__version__ = "0.1.0"
|