atp-protocol 1.0.0__py3-none-any.whl → 1.2.0__py3-none-any.whl
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.
- atp/__init__.py +4 -7
- atp/config.py +1 -1
- atp/middleware.py +19 -32
- {atp_protocol-1.0.0.dist-info → atp_protocol-1.2.0.dist-info}/METADATA +90 -181
- atp_protocol-1.2.0.dist-info/RECORD +9 -0
- atp/solana_utils.py +0 -1001
- atp/token_prices.py +0 -97
- atp/utils.py +0 -174
- atp/vault.py +0 -75
- atp_protocol-1.0.0.dist-info/RECORD +0 -13
- {atp_protocol-1.0.0.dist-info → atp_protocol-1.2.0.dist-info}/LICENSE +0 -0
- {atp_protocol-1.0.0.dist-info → atp_protocol-1.2.0.dist-info}/WHEEL +0 -0
atp/__init__.py
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
from atp.middleware import (
|
|
4
|
-
ATPSettlementMiddleware,
|
|
5
|
-
create_settlement_middleware,
|
|
6
|
-
)
|
|
1
|
+
from atp.middleware import ATPSettlementMiddleware, create_settlement_middleware
|
|
2
|
+
from atp.settlement_client import SettlementServiceClient
|
|
7
3
|
|
|
8
4
|
__all__ = [
|
|
9
5
|
"ATPSettlementMiddleware",
|
|
10
6
|
"create_settlement_middleware",
|
|
11
|
-
|
|
7
|
+
"SettlementServiceClient",
|
|
8
|
+
]
|
atp/config.py
CHANGED
atp/middleware.py
CHANGED
|
@@ -67,8 +67,6 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
|
|
|
67
67
|
recipient_pubkey: Optional[str] = None,
|
|
68
68
|
skip_preflight: bool = False,
|
|
69
69
|
commitment: str = "confirmed",
|
|
70
|
-
usage_response_key: str = "usage",
|
|
71
|
-
include_usage_in_response: bool = True,
|
|
72
70
|
require_wallet: bool = True,
|
|
73
71
|
settlement_service_url: Optional[str] = None,
|
|
74
72
|
):
|
|
@@ -92,8 +90,6 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
|
|
|
92
90
|
This wallet receives the main payment (after processing fee). Required.
|
|
93
91
|
skip_preflight: Whether to skip preflight simulation for Solana transactions.
|
|
94
92
|
commitment: Solana commitment level (processed|confirmed|finalized).
|
|
95
|
-
usage_response_key: Key in response JSON where usage data is located (default: "usage").
|
|
96
|
-
include_usage_in_response: Whether to add usage/cost info to the response.
|
|
97
93
|
require_wallet: Whether to require wallet private key (if False, skips settlement when missing).
|
|
98
94
|
settlement_service_url: Base URL of the settlement service. If not provided, uses
|
|
99
95
|
ATP_SETTLEMENT_URL environment variable (default: http://localhost:8001).
|
|
@@ -119,8 +115,6 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
|
|
|
119
115
|
)
|
|
120
116
|
self.skip_preflight = skip_preflight
|
|
121
117
|
self.commitment = commitment
|
|
122
|
-
self.usage_response_key = usage_response_key
|
|
123
|
-
self.include_usage_in_response = include_usage_in_response
|
|
124
118
|
self.require_wallet = require_wallet
|
|
125
119
|
# Always use settlement service - initialize client with config value or provided URL
|
|
126
120
|
service_url = (
|
|
@@ -146,10 +140,9 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
|
|
|
146
140
|
"""
|
|
147
141
|
Extract usage information from response body.
|
|
148
142
|
|
|
149
|
-
|
|
150
|
-
1.
|
|
151
|
-
2.
|
|
152
|
-
3. Try nested structures (usage.usage, meta.usage, etc.)
|
|
143
|
+
Automatically detects usage data using multiple strategies:
|
|
144
|
+
1. Check if the entire response contains usage-like keys
|
|
145
|
+
2. Try nested structures with common usage key names (usage, token_usage, etc.)
|
|
153
146
|
|
|
154
147
|
The usage data is then sent to the settlement service for parsing,
|
|
155
148
|
so we just need to extract the raw usage object.
|
|
@@ -160,12 +153,7 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
|
|
|
160
153
|
return None
|
|
161
154
|
data = json.loads(body_str)
|
|
162
155
|
|
|
163
|
-
# Strategy 1:
|
|
164
|
-
usage = data.get(self.usage_response_key)
|
|
165
|
-
if usage and isinstance(usage, dict):
|
|
166
|
-
return usage
|
|
167
|
-
|
|
168
|
-
# Strategy 2: Check if the entire response is usage-like
|
|
156
|
+
# Strategy 1: Check if the entire response is usage-like
|
|
169
157
|
if isinstance(data, dict):
|
|
170
158
|
# Check for common usage keys at top level
|
|
171
159
|
usage_keys = [
|
|
@@ -182,7 +170,7 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
|
|
|
182
170
|
if any(key in data for key in usage_keys):
|
|
183
171
|
return data
|
|
184
172
|
|
|
185
|
-
# Strategy
|
|
173
|
+
# Strategy 2: Try nested structures
|
|
186
174
|
# Check for usage nested in common locations
|
|
187
175
|
for nested_key in [
|
|
188
176
|
"usage",
|
|
@@ -284,21 +272,20 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
|
|
|
284
272
|
detail=f"Settlement failed: {str(e)}",
|
|
285
273
|
)
|
|
286
274
|
|
|
287
|
-
#
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
)
|
|
275
|
+
# Always include settlement information in the response
|
|
276
|
+
try:
|
|
277
|
+
response_data = json.loads(
|
|
278
|
+
response_body.decode("utf-8")
|
|
279
|
+
)
|
|
280
|
+
response_data["atp_settlement"] = payment_result
|
|
281
|
+
response_data["atp_usage"] = usage
|
|
282
|
+
response_body = json.dumps(response_data).encode(
|
|
283
|
+
"utf-8"
|
|
284
|
+
)
|
|
285
|
+
except Exception as e:
|
|
286
|
+
logger.warning(
|
|
287
|
+
f"Failed to add settlement info to response: {e}"
|
|
288
|
+
)
|
|
302
289
|
|
|
303
290
|
return Response(
|
|
304
291
|
content=response_body,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: atp-protocol
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: ATP Protocol - Agentic Trade Protocol. The easiest way to enable agent-to-agent payments powered by Solana.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: atp,atp-protocol,solana,blockchain,cryptocurrency,payment-gated,agent-to-agent,agent payments,agent execution,payment settlement,solana payments,usdc,sol,fastapi,agent api,payment gateway,settlement service,agent marketplace,decentralized payments,web3,crypto payments,agent infrastructure,payment middleware,automated settlement
|
|
@@ -17,13 +17,14 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
17
17
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
18
18
|
Classifier: Topic :: Office/Business :: Financial
|
|
19
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Dist: fastapi
|
|
20
21
|
Requires-Dist: httpx
|
|
21
22
|
Requires-Dist: loguru
|
|
22
23
|
Requires-Dist: pydantic
|
|
23
24
|
Requires-Dist: python-dotenv
|
|
24
25
|
Requires-Dist: setuptools
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: starlette
|
|
27
|
+
Requires-Dist: swarms
|
|
27
28
|
Project-URL: Documentation, https://github.com/The-Swarm-Corporation/ATP-Protocol
|
|
28
29
|
Project-URL: Homepage, https://github.com/The-Swarm-Corporation/ATP-Protocol
|
|
29
30
|
Project-URL: Repository, https://github.com/The-Swarm-Corporation/ATP-Protocol
|
|
@@ -254,33 +255,46 @@ stateDiagram-v2
|
|
|
254
255
|
|
|
255
256
|
## ATP Settlement Middleware
|
|
256
257
|
|
|
257
|
-
The ATP
|
|
258
|
+
The ATP Settlement Middleware enables **automatic payment processing** for any FastAPI endpoint. Unlike the main ATP Gateway (which uses a 402 challenge), the middleware handles payment **automatically after** your endpoint executes—perfect for APIs that want seamless billing.
|
|
258
259
|
|
|
259
|
-
### How
|
|
260
|
+
### How It Works
|
|
260
261
|
|
|
261
|
-
The
|
|
262
|
+
The middleware intercepts requests, executes your endpoint, then automatically processes payment:
|
|
262
263
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
264
|
+
```mermaid
|
|
265
|
+
sequenceDiagram
|
|
266
|
+
autonumber
|
|
267
|
+
participant C as Client
|
|
268
|
+
participant M as Middleware
|
|
269
|
+
participant E as Endpoint
|
|
270
|
+
participant SS as Settlement Service
|
|
271
|
+
participant S as Solana
|
|
270
272
|
|
|
271
|
-
|
|
273
|
+
C->>M: POST /v1/chat<br/>(x-wallet-private-key header)
|
|
274
|
+
M->>E: Forward request
|
|
275
|
+
E-->>M: Response + usage data
|
|
276
|
+
M->>M: Extract token usage<br/>(auto-detects format)
|
|
277
|
+
M->>SS: Calculate payment<br/>(usage → USD → SOL/USDC)
|
|
278
|
+
SS->>SS: Split payment<br/>(95% recipient, 5% treasury)
|
|
279
|
+
SS->>S: Send payment transaction
|
|
280
|
+
S-->>SS: Transaction signature
|
|
281
|
+
SS-->>M: Settlement details
|
|
282
|
+
M->>M: Add settlement info<br/>to response
|
|
283
|
+
M-->>C: Response + atp_settlement
|
|
284
|
+
```
|
|
272
285
|
|
|
273
|
-
|
|
274
|
-
|---------|-----------------|------------|
|
|
275
|
-
| **Payment Flow** | Two-step: 402 challenge → settle | Automatic: single request |
|
|
276
|
-
| **Response** | Returns 402 with payment challenge | Returns normal response + settlement info |
|
|
277
|
-
| **Integration** | Requires two API calls | Single API call with wallet header |
|
|
278
|
-
| **Use Case** | Pay-to-unlock results | Automatic per-request billing |
|
|
279
|
-
| **Wallet Key** | Provided during settlement | Provided in request header |
|
|
286
|
+
**Step-by-step:**
|
|
280
287
|
|
|
281
|
-
|
|
288
|
+
1. **Client sends request** with wallet private key in header (`x-wallet-private-key`)
|
|
289
|
+
2. **Middleware forwards** request to your endpoint
|
|
290
|
+
3. **Endpoint executes** and returns response with usage data
|
|
291
|
+
4. **Middleware extracts** token counts (supports OpenAI, Anthropic, Google, etc.)
|
|
292
|
+
5. **Settlement service calculates** cost: `(input_tokens × input_rate + output_tokens × output_rate) / 1M`
|
|
293
|
+
6. **Settlement service splits** payment: 95% to recipient, 5% to Swarms Treasury
|
|
294
|
+
7. **Settlement service sends** Solana transaction
|
|
295
|
+
8. **Middleware adds** settlement info to response and returns to client
|
|
282
296
|
|
|
283
|
-
|
|
297
|
+
### Quick Start
|
|
284
298
|
|
|
285
299
|
```python
|
|
286
300
|
from fastapi import FastAPI
|
|
@@ -291,202 +305,97 @@ app = FastAPI()
|
|
|
291
305
|
|
|
292
306
|
app.add_middleware(
|
|
293
307
|
ATPSettlementMiddleware,
|
|
294
|
-
allowed_endpoints=[
|
|
295
|
-
|
|
296
|
-
"/v1/completions",
|
|
297
|
-
"/v1/agent/execute",
|
|
298
|
-
],
|
|
299
|
-
input_cost_per_million_usd=10.0, # $10 per million input tokens
|
|
308
|
+
allowed_endpoints=["/v1/chat", "/v1/completions"],
|
|
309
|
+
input_cost_per_million_usd=10.0, # $10 per million input tokens
|
|
300
310
|
output_cost_per_million_usd=30.0, # $30 per million output tokens
|
|
301
|
-
|
|
302
|
-
payment_token=PaymentToken.SOL,
|
|
303
|
-
recipient_pubkey="YourPublicKeyHere", # Required: endpoint host receives payment
|
|
304
|
-
skip_preflight=False, # Skip Solana transaction preflight simulation
|
|
305
|
-
commitment="confirmed", # Solana commitment level
|
|
306
|
-
usage_response_key="usage", # Key in response where usage data is located
|
|
307
|
-
include_usage_in_response=True, # Add usage/cost info to response
|
|
308
|
-
require_wallet=True, # Require wallet key (if False, skips settlement when missing)
|
|
311
|
+
recipient_pubkey="YourPublicKeyHere", # Your wallet receives 95%
|
|
312
|
+
payment_token=PaymentToken.SOL,
|
|
309
313
|
)
|
|
310
314
|
```
|
|
311
315
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
- **`allowed_endpoints`** (required): List of endpoint paths to apply settlement to (exact matches only)
|
|
315
|
-
- **`input_cost_per_million_usd`** (required): Cost per million input tokens in USD
|
|
316
|
-
- **`output_cost_per_million_usd`** (required): Cost per million output tokens in USD
|
|
317
|
-
- **`wallet_private_key_header`** (default: `"x-wallet-private-key"`): HTTP header name containing the wallet private key
|
|
318
|
-
- **`payment_token`** (default: `PaymentToken.SOL`): Token to use for payment (SOL or USDC)
|
|
319
|
-
- **`recipient_pubkey`** (required): Solana public key of the recipient wallet (endpoint host receives main payment)
|
|
320
|
-
- **`skip_preflight`** (default: `False`): Whether to skip preflight simulation for Solana transactions
|
|
321
|
-
- **`commitment`** (default: `"confirmed"`): Solana commitment level (`processed`|`confirmed`|`finalized`)
|
|
322
|
-
- **`usage_response_key`** (default: `"usage"`): Key in response JSON where usage data is located
|
|
323
|
-
- **`include_usage_in_response`** (default: `True`): Whether to add usage/cost info to the response
|
|
324
|
-
- **`require_wallet`** (default: `True`): Whether to require wallet private key (if False, skips settlement when missing)
|
|
325
|
-
|
|
326
|
-
### Usage Example
|
|
327
|
-
|
|
328
|
-
**Client Request:**
|
|
316
|
+
**Client request:**
|
|
329
317
|
```bash
|
|
330
318
|
curl -X POST http://localhost:8000/v1/chat \
|
|
331
|
-
-H "Content-Type: application/json" \
|
|
332
319
|
-H "x-wallet-private-key: [1,2,3,...]" \
|
|
333
|
-
-d '{"message": "Hello
|
|
320
|
+
-d '{"message": "Hello!"}'
|
|
334
321
|
```
|
|
335
322
|
|
|
336
|
-
**
|
|
323
|
+
**Your endpoint:**
|
|
337
324
|
```python
|
|
338
325
|
@app.post("/v1/chat")
|
|
339
|
-
async def
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
"output": "Hello! This is a response from the chat endpoint.",
|
|
326
|
+
async def chat(request: dict):
|
|
327
|
+
return {
|
|
328
|
+
"output": "Response here",
|
|
343
329
|
"usage": {
|
|
344
|
-
"input_tokens": 150,
|
|
345
|
-
"output_tokens": 50,
|
|
346
|
-
|
|
347
|
-
},
|
|
330
|
+
"input_tokens": 150,
|
|
331
|
+
"output_tokens": 50,
|
|
332
|
+
}
|
|
348
333
|
}
|
|
349
|
-
return JSONResponse(content=response_data)
|
|
350
334
|
```
|
|
351
335
|
|
|
352
|
-
**Response
|
|
336
|
+
**Response includes settlement:**
|
|
353
337
|
```json
|
|
354
338
|
{
|
|
355
|
-
"output": "
|
|
356
|
-
"usage": {
|
|
357
|
-
"input_tokens": 150,
|
|
358
|
-
"output_tokens": 50,
|
|
359
|
-
"total_tokens": 200
|
|
360
|
-
},
|
|
361
|
-
"atp_usage": {
|
|
362
|
-
"input_tokens": 150,
|
|
363
|
-
"output_tokens": 50,
|
|
364
|
-
"total_tokens": 200
|
|
365
|
-
},
|
|
339
|
+
"output": "Response here",
|
|
340
|
+
"usage": {"input_tokens": 150, "output_tokens": 50},
|
|
366
341
|
"atp_settlement": {
|
|
367
342
|
"status": "paid",
|
|
368
343
|
"transaction_signature": "5j7s8K9...",
|
|
369
|
-
"pricing": {
|
|
370
|
-
"usd_cost": 0.003,
|
|
371
|
-
"source": "middleware_rates",
|
|
372
|
-
"input_tokens": 150,
|
|
373
|
-
"output_tokens": 50,
|
|
374
|
-
"total_tokens": 200,
|
|
375
|
-
"input_cost_per_million_usd": 10.0,
|
|
376
|
-
"output_cost_per_million_usd": 30.0,
|
|
377
|
-
"input_cost_usd": 0.0015,
|
|
378
|
-
"output_cost_usd": 0.0015
|
|
379
|
-
},
|
|
380
344
|
"payment": {
|
|
381
|
-
"total_amount_lamports": 300000,
|
|
382
345
|
"total_amount_sol": 0.0003,
|
|
383
|
-
"
|
|
384
|
-
"treasury": {
|
|
385
|
-
"pubkey": "7MaX4muAn8ZQREJxnupm8sgokwFHujgrGfH9Qn81BuEV",
|
|
386
|
-
"amount_lamports": 15000,
|
|
387
|
-
"amount_sol": 0.000015,
|
|
388
|
-
"amount_usd": 0.00015
|
|
389
|
-
},
|
|
390
|
-
"recipient": {
|
|
391
|
-
"pubkey": "YourPublicKeyHere",
|
|
392
|
-
"amount_lamports": 285000,
|
|
393
|
-
"amount_sol": 0.000285,
|
|
394
|
-
"amount_usd": 0.00285
|
|
395
|
-
}
|
|
346
|
+
"recipient": {"amount_sol": 0.000285},
|
|
347
|
+
"treasury": {"amount_sol": 0.000015}
|
|
396
348
|
}
|
|
397
349
|
}
|
|
398
350
|
}
|
|
399
351
|
```
|
|
400
352
|
|
|
401
|
-
###
|
|
353
|
+
### Configuration
|
|
402
354
|
|
|
403
|
-
|
|
355
|
+
| Parameter | Required | Description |
|
|
356
|
+
|-----------|----------|-------------|
|
|
357
|
+
| `allowed_endpoints` | ✅ | List of paths to apply settlement (e.g., `["/v1/chat"]`) |
|
|
358
|
+
| `input_cost_per_million_usd` | ✅ | Cost per million input tokens |
|
|
359
|
+
| `output_cost_per_million_usd` | ✅ | Cost per million output tokens |
|
|
360
|
+
| `recipient_pubkey` | ✅ | Your Solana wallet (receives 95% of payment) |
|
|
361
|
+
| `wallet_private_key_header` | ❌ | Header name for wallet key (default: `x-wallet-private-key`) |
|
|
362
|
+
| `payment_token` | ❌ | `PaymentToken.SOL` or `PaymentToken.USDC` (default: SOL) |
|
|
363
|
+
| `require_wallet` | ❌ | Require wallet key or skip settlement (default: `True`) |
|
|
364
|
+
| `settlement_service_url` | ❌ | Settlement service URL (default: from `ATP_SETTLEMENT_URL` env) |
|
|
404
365
|
|
|
405
|
-
|
|
406
|
-
- **Anthropic**: `input_tokens`, `output_tokens`, `total_tokens`
|
|
407
|
-
- **Google/Gemini**: `promptTokenCount`, `candidatesTokenCount`, `totalTokenCount`
|
|
408
|
-
- **Cohere**: `tokens` (total), or `input_tokens`/`output_tokens` separately
|
|
409
|
-
- **Generic**: `input_tokens`, `output_tokens`, `total_tokens`
|
|
410
|
-
- **Nested**: `usage.prompt_tokens`, `meta.usage`, `statistics`, etc.
|
|
366
|
+
### Payment Calculation
|
|
411
367
|
|
|
412
|
-
The middleware
|
|
413
|
-
1. The configured `usage_response_key` (default: `"usage"`)
|
|
414
|
-
2. Top-level keys in the response
|
|
415
|
-
3. Nested structures (`usage`, `meta.usage`, `statistics`, etc.)
|
|
368
|
+
The middleware uses your configured rates to calculate cost:
|
|
416
369
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
sequenceDiagram
|
|
421
|
-
autonumber
|
|
422
|
-
participant C as Client
|
|
423
|
-
participant M as Middleware
|
|
424
|
-
participant E as Endpoint
|
|
425
|
-
participant S as Solana
|
|
426
|
-
|
|
427
|
-
C->>M: POST /v1/chat<br/>(x-wallet-private-key header)
|
|
428
|
-
M->>E: Forward request
|
|
429
|
-
E-->>M: Response + usage data
|
|
430
|
-
M->>M: Extract usage tokens<br/>(normalize format)
|
|
431
|
-
M->>M: Calculate USD cost<br/>(from token counts)
|
|
432
|
-
M->>M: Fetch token price<br/>(SOL/USDC)
|
|
433
|
-
M->>M: Calculate payment amounts<br/>(with 5% fee split)
|
|
434
|
-
M->>S: Send split payment tx<br/>(recipient + treasury)
|
|
435
|
-
S-->>M: Transaction signature
|
|
436
|
-
M->>M: Add settlement info<br/>to response
|
|
437
|
-
M-->>C: Response + atp_settlement
|
|
370
|
+
```
|
|
371
|
+
usd_cost = (input_tokens / 1,000,000 × input_rate) + (output_tokens / 1,000,000 × output_rate)
|
|
372
|
+
token_amount = usd_cost / token_price_usd
|
|
438
373
|
```
|
|
439
374
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
- **Total Payment**: `usd_cost / token_price_usd`
|
|
445
|
-
- **Swarms Treasury Fee**: `5%` of total (from `config.SETTLEMENT_FEE_PERCENT`)
|
|
446
|
-
- **Recipient Amount**: `95%` of total (endpoint host receives this)
|
|
447
|
-
|
|
448
|
-
The fee is **taken from the total** (not added on top), so the recipient receives the net amount after fees.
|
|
449
|
-
|
|
450
|
-
### Error Handling
|
|
451
|
-
|
|
452
|
-
- **Missing wallet key**: Returns `401 Unauthorized` if `require_wallet=True` (default)
|
|
453
|
-
- **Missing usage data**: Logs warning and returns original response (no settlement)
|
|
454
|
-
- **Payment failure**: Returns `500 Internal Server Error` with error details
|
|
455
|
-
- **Invalid private key**: Returns `500 Internal Server Error` with parsing error
|
|
456
|
-
|
|
457
|
-
### Custom API Key Integration
|
|
375
|
+
Payment is split automatically:
|
|
376
|
+
- **95%** → `recipient_pubkey` (your wallet)
|
|
377
|
+
- **5%** → Swarms Treasury (processing fee)
|
|
458
378
|
|
|
459
|
-
|
|
379
|
+
The fee is **deducted from the total** (not added on top).
|
|
460
380
|
|
|
461
|
-
|
|
462
|
-
# Simple in-memory mapping (replace with database in production)
|
|
463
|
-
API_KEY_TO_WALLET = {
|
|
464
|
-
"user_api_key_123": "[1,2,3,...]", # Solana private key
|
|
465
|
-
}
|
|
381
|
+
### Supported Usage Formats
|
|
466
382
|
|
|
467
|
-
|
|
468
|
-
"""Custom dependency to map API keys to wallet private keys."""
|
|
469
|
-
if api_key not in API_KEY_TO_WALLET:
|
|
470
|
-
raise HTTPException(status_code=401, detail="Invalid API key")
|
|
471
|
-
return API_KEY_TO_WALLET[api_key]
|
|
383
|
+
The middleware auto-detects usage from common API formats:
|
|
472
384
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
385
|
+
- **OpenAI**: `prompt_tokens`, `completion_tokens`
|
|
386
|
+
- **Anthropic**: `input_tokens`, `output_tokens`
|
|
387
|
+
- **Google/Gemini**: `promptTokenCount`, `candidatesTokenCount`
|
|
388
|
+
- **Generic**: `input_tokens`, `output_tokens`, `total_tokens`
|
|
389
|
+
- **Nested**: `usage.*`, `meta.usage`, `statistics.*`
|
|
478
390
|
|
|
479
|
-
|
|
480
|
-
- You want automatic, per-request billing
|
|
481
|
-
- Your API already returns usage data
|
|
482
|
-
- You want a single-request flow (no 402 challenge)
|
|
483
|
-
- You're building a service that charges per API call
|
|
391
|
+
### Middleware vs. Main Protocol
|
|
484
392
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
-
|
|
488
|
-
|
|
489
|
-
|
|
393
|
+
| Feature | Main Gateway | Middleware |
|
|
394
|
+
|---------|--------------|------------|
|
|
395
|
+
| **Flow** | Two-step: 402 challenge → settle | Automatic: single request |
|
|
396
|
+
| **Use Case** | Pay-to-unlock results | Per-request billing |
|
|
397
|
+
| **Integration** | Two API calls | One API call |
|
|
490
398
|
|
|
491
|
-
|
|
399
|
+
**Use middleware for:** Automatic billing on every request
|
|
400
|
+
**Use main protocol for:** Explicit payment approval before results
|
|
492
401
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
atp/__init__.py,sha256=fpKQQCi9HQEj4t2Rs5ng5qmp0KwGV6bZIl1tnS-3HQ8,251
|
|
2
|
+
atp/config.py,sha256=lYERbrySRTuyS_jeaAnLHYuBEQNLqaKLQTy_nEFP7lY,2041
|
|
3
|
+
atp/middleware.py,sha256=GlRBXEba_hlGMPi69LAGUJSQsKfmwSnAENKZQ9QcXhU,13185
|
|
4
|
+
atp/schemas.py,sha256=iASVBPpAhrO-LDXs2UC9ABtfV1oDYsu4kZcz3dVeJNA,6220
|
|
5
|
+
atp/settlement_client.py,sha256=jfvhxDqp2kDISWG7tjX5s88goAPxp-lMXvuJtpMyOys,6742
|
|
6
|
+
atp_protocol-1.2.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
7
|
+
atp_protocol-1.2.0.dist-info/METADATA,sha256=r-Q1CFshMWPS-jftoGwI7OuPcj8B609IRGcBe00VX0E,14295
|
|
8
|
+
atp_protocol-1.2.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
9
|
+
atp_protocol-1.2.0.dist-info/RECORD,,
|