atp-protocol 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,492 @@
1
+ Metadata-Version: 2.3
2
+ Name: atp-protocol
3
+ Version: 1.0.0
4
+ Summary: ATP Protocol - Agentic Trade Protocol. The easiest way to enable agent-to-agent payments powered by Solana.
5
+ License: MIT
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
7
+ Author: The Swarm Corporation
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
18
+ Classifier: Topic :: Office/Business :: Financial
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Dist: httpx
21
+ Requires-Dist: loguru
22
+ Requires-Dist: pydantic
23
+ Requires-Dist: python-dotenv
24
+ Requires-Dist: setuptools
25
+ Requires-Dist: solana
26
+ Requires-Dist: solders
27
+ Project-URL: Documentation, https://github.com/The-Swarm-Corporation/ATP-Protocol
28
+ Project-URL: Homepage, https://github.com/The-Swarm-Corporation/ATP-Protocol
29
+ Project-URL: Repository, https://github.com/The-Swarm-Corporation/ATP-Protocol
30
+ Description-Content-Type: text/markdown
31
+
32
+ # ATP-Protocol
33
+
34
+ ATP Protocol is a **payment-gated agent execution API** that makes **agent-to-agent payments** and “pay to unlock results” easy on **Solana**, with a simple client integration (two endpoints + a Solana payment).
35
+
36
+ At a high level:
37
+
38
+ - An agent (or any client) requests work from another agent via the ATP Gateway.
39
+ - The Gateway executes the upstream agent immediately, but **returns a 402 challenge** instead of the result.
40
+ - The requester pays **once** to the agent treasury (in **SOL** or **USDC**).
41
+ - After settlement, the Gateway releases the stored agent output.
42
+
43
+ The ATP Gateway exposes:
44
+
45
+ - `POST /v1/agent/trade`: execute + return payment challenge (402)
46
+ - `POST /v1/agent/settle`: facilitator signs+submits payment (using provided private key) + releases output
47
+ - optional helper endpoints for token price/payment info
48
+
49
+ ---
50
+
51
+ ## One simple end-to-end example (trade → settle)
52
+
53
+ Run the server, then run:
54
+
55
+ ```bash
56
+ export ATP_BASE_URL="http://localhost:8000"
57
+ export ATP_USER_WALLET="<YOUR_SOLANA_PUBKEY>"
58
+ export ATP_PRIVATE_KEY="<YOUR_PRIVATE_KEY_STRING>"
59
+
60
+ # Safety switch: settlement will broadcast a real SOL transaction
61
+ export ATP_ALLOW_SPEND="true"
62
+
63
+ python full_flow_example.py
64
+ ```
65
+
66
+ Notes:
67
+ - The first call (`/v1/agent/trade`) returns **HTTP 402** with a `job_id` and the payment challenge JSON.
68
+ - The second call (`/v1/agent/settle`) signs+sends the SOL payment in-memory and returns **HTTP 200** with `agent_output`.
69
+
70
+ Server-side pricing (optional):
71
+ - Set `INPUT_COST_PER_MILLION_USD` and/or `OUTPUT_COST_PER_MILLION_USD` on the server to compute `usd_cost` from `usage` token counts.
72
+ - If not set (or if token counts are missing), the gateway falls back to upstream `usage.total_cost` (and then a small default).
73
+
74
+ ---
75
+
76
+ ## Conceptual purpose
77
+
78
+ ATP exists to solve a common agentic workflow problem:
79
+
80
+ - Agents can call other agents (“agent tools”, “specialist agents”, “market-data agents”), but **payments and settlement** are usually ad-hoc.
81
+ - ATP standardizes **a simple handshake**: *execute → challenge → pay → settle → release*.
82
+ - Because the settlement happens on Solana, it’s **cheap**, **fast**, and can be done by **another agent** programmatically (no human-in-the-loop required).
83
+
84
+ Key design goals:
85
+
86
+ - **Agent-to-agent friendly**: the “client” can be another agent, a bot, or a backend service.
87
+ - **Simple integration**: clients can settle by providing a private key string for a single request (used in-memory only).
88
+ - **Token flexibility**: support SOL today, and USDC as a stable-priced option.
89
+
90
+ ---
91
+
92
+ ## Core actors
93
+
94
+ - **Requester (Agent A)**: wants work done (submits the task, later pays and settles).
95
+ - **ATP Gateway**: runs the upstream agent, produces the payment challenge, holds the result temporarily.
96
+ - **Upstream Agent Service (Swarms API)**: executes the requested agent workload.
97
+ - **Solana**: settlement rail (payment transaction + signature).
98
+ - **Facilitator**: signs+submits the payment transaction during settlement.
99
+ - **Agent Treasury**: receives the payment (minus the fee split logic described below).
100
+ - **Swarms Treasury**: receives the **5% settlement fee**.
101
+ - **Temporary lockbox**: the gateway holds the output until paid (expires after a TTL).
102
+
103
+ ---
104
+
105
+ ## How it works (step-by-step)
106
+
107
+ ### 1) Request a trade (create challenge)
108
+
109
+ The requester calls:
110
+
111
+ - `POST /v1/agent/trade`
112
+
113
+ with:
114
+
115
+ - `agent_config`: full agent spec (see `atp/schemas.py:AgentSpec`)
116
+ - `task`: what to do
117
+ - `user_wallet`: payer public key (used during verification)
118
+ - `payment_token`: `SOL` or `USDC`
119
+ - optional `history` / `img` / `imgs`
120
+
121
+ ### 2) Gateway executes the agent immediately
122
+
123
+ The Gateway forwards the request to the upstream agent service (`SWARMS_API_URL`) and waits for completion.
124
+
125
+ ### 3) Gateway computes the price + fee split
126
+
127
+ The Gateway:
128
+
129
+ - reads the USD cost from upstream usage (`usage.total_cost`, with a fallback),
130
+ - fetches token/USD price (SOL via CoinGecko, USDC treated as $1),
131
+ - computes the **total payment** and the **5% settlement fee**.
132
+
133
+ Important: the fee is **taken from the total** (not added on top):
134
+ \[
135
+ \text{total} = \frac{\text{usd\_cost}}{\text{token\_price}}
136
+ \quad
137
+ \text{fee} = 0.05 \cdot \text{total}
138
+ \quad
139
+ \text{agent\_receives} = \text{total} - \text{fee}
140
+ \]
141
+
142
+ ### 4) Gateway stores the result (locked) with a TTL
143
+
144
+ The agent output is held in a temporary lockbox under a generated `job_id`.
145
+
146
+ If the requester never pays, the job expires automatically (default TTL: 10 minutes).
147
+
148
+ ### 5) Gateway returns a 402 Payment Required challenge
149
+
150
+ Instead of returning the agent output, the Gateway returns **HTTP 402** with a JSON payload containing:
151
+
152
+ - `job_id`
153
+ - `recipient` (the agent treasury pubkey)
154
+ - amount to pay (in lamports or USDC micro-units)
155
+ - a memo format like `ATP:{job_id}`
156
+ - a fee breakdown (5% to Swarms treasury)
157
+ - TTL info
158
+
159
+ ### 6) Requester pays on Solana
160
+
161
+ The requester provides a private key string during settlement; the gateway signs+sends the SOL payment transaction in-memory.
162
+
163
+ ### 7) Settle to unlock
164
+
165
+ The requester calls:
166
+
167
+ - `POST /v1/agent/settle`
168
+
169
+ with:
170
+
171
+ - `job_id`
172
+ - `private_key`
173
+
174
+ ### 8) Gateway verifies and releases the output
175
+
176
+ The Gateway:
177
+
178
+ - looks up the pending job by `job_id`,
179
+ - signs+sends the on-chain payment transaction and verifies it succeeded,
180
+ - releases the output exactly once (prevents double-settlement),
181
+ - returns the stored `agent_output` and settlement details.
182
+
183
+ ---
184
+
185
+ ## Diagrams
186
+
187
+ ### Architecture overview
188
+
189
+ ```mermaid
190
+ flowchart LR
191
+ A["Requester<br/>(Agent A / App / Bot)"] -->|POST /v1/agent/trade| G["ATP Gateway<br/>FastAPI"]
192
+ G -->|Execute task| S["Swarms Agent API<br/>Upstream execution"]
193
+ S -->|Result + usage cost| G
194
+
195
+ A -->|POST /v1/agent/settle<br/>(job_id, private_key)| G
196
+ G <-->|Send payment tx| C["Solana<br/>(SOL / USDC)"]
197
+ G -->|Verify signature status| C
198
+ G -->|Unlocked agent output| A
199
+
200
+ C --> T1[Agent Treasury]
201
+ C --> T2["Swarms Treasury<br/>(5% fee)"]
202
+ ```
203
+
204
+ ### End-to-end sequence (challenge → payment → settlement)
205
+
206
+ ```mermaid
207
+ sequenceDiagram
208
+ autonumber
209
+ participant A as Requester (Agent A)
210
+ participant G as ATP Gateway
211
+ participant S as Swarms Agent API
212
+ participant C as Solana
213
+
214
+ A->>G: POST /v1/agent/trade (agent_config, task, wallet, token)
215
+ G->>S: Execute agent task
216
+ S-->>G: outputs + usage.total_cost
217
+ G->>G: Compute total + 5% fee split<br/>(fetch token price)
218
+ G->>G: Lock result (job_id, ttl)
219
+ G-->>A: 402 Payment Required<br/>(job_id + payment instruction)
220
+
221
+ A->>G: POST /v1/agent/settle (job_id, private_key)
222
+ G->>C: Send payment tx (SOL/USDC)<br/>recipient=Agent Treasury
223
+ C-->>G: tx_signature
224
+ G->>G: Load locked job by job_id
225
+ G->>C: Verify tx signature success
226
+ G->>G: Release output once
227
+ G-->>A: 200 OK (agent_output + settlement_details)
228
+ ```
229
+
230
+ ### Job lifecycle / state machine
231
+
232
+ ```mermaid
233
+ stateDiagram-v2
234
+ [*] --> Created: /v1/agent/trade<br/>job_id minted
235
+ Created --> Locked: result locked until paid
236
+ Locked --> Expired: TTL elapses<br/>(no settlement)
237
+ Locked --> Settling: /v1/agent/settle<br/>signed payment submitted
238
+ Settling --> Released: signature verified<br/>output released
239
+ Settling --> Locked: verification failed<br/>job remains until TTL
240
+ Released --> [*]
241
+ Expired --> [*]
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Client expectations (what you can rely on)
247
+
248
+ - **Two-call integration**: request work via `/v1/agent/trade`, then unlock via `/v1/agent/settle`.
249
+ - **Single payment**: you pay once to the `recipient` address returned by the 402 challenge.
250
+ - **Clear fee disclosure**: the 402 includes a breakdown showing the **5% settlement fee** and who receives it.
251
+ - **Time-bounded**: each `job_id` expires after `ttl_seconds` if you don't settle in time.
252
+
253
+ ---
254
+
255
+ ## ATP Settlement Middleware
256
+
257
+ The ATP Protocol also provides a **FastAPI middleware** that enables **automatic payment deduction** for any configured endpoint. Unlike the main ATP Gateway (which uses a 402 challenge pattern), the middleware automatically deducts payment **after** the endpoint executes successfully, making it ideal for APIs that want seamless, automatic settlement.
258
+
259
+ ### How the Middleware Works
260
+
261
+ The `ATPSettlementMiddleware` intercepts requests to configured endpoints and:
262
+
263
+ 1. **Extracts wallet private key** from request headers (default: `x-wallet-private-key`)
264
+ 2. **Executes the endpoint** normally (passes request through)
265
+ 3. **Extracts usage data** from the response (token counts from various API formats)
266
+ 4. **Calculates cost** based on configured rates (`input_cost_per_million_usd`, `output_cost_per_million_usd`)
267
+ 5. **Automatically deducts payment** from the provided wallet via Solana transaction
268
+ 6. **Splits payment** between recipient (endpoint host) and Swarms Treasury (5% fee)
269
+ 7. **Adds settlement info** to the response (optional)
270
+
271
+ ### Key Differences from Main ATP Protocol
272
+
273
+ | Feature | Main ATP Gateway | Middleware |
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 |
280
+
281
+ ### Middleware Configuration
282
+
283
+ Add the middleware to your FastAPI app:
284
+
285
+ ```python
286
+ from fastapi import FastAPI
287
+ from atp.middleware import ATPSettlementMiddleware
288
+ from atp.schemas import PaymentToken
289
+
290
+ app = FastAPI()
291
+
292
+ app.add_middleware(
293
+ ATPSettlementMiddleware,
294
+ allowed_endpoints=[
295
+ "/v1/chat",
296
+ "/v1/completions",
297
+ "/v1/agent/execute",
298
+ ],
299
+ input_cost_per_million_usd=10.0, # $10 per million input tokens
300
+ output_cost_per_million_usd=30.0, # $30 per million output tokens
301
+ wallet_private_key_header="x-wallet-private-key", # Header name for wallet key
302
+ payment_token=PaymentToken.SOL, # SOL or USDC
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)
309
+ )
310
+ ```
311
+
312
+ ### Configuration Parameters
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:**
329
+ ```bash
330
+ curl -X POST http://localhost:8000/v1/chat \
331
+ -H "Content-Type: application/json" \
332
+ -H "x-wallet-private-key: [1,2,3,...]" \
333
+ -d '{"message": "Hello, world!"}'
334
+ ```
335
+
336
+ **Endpoint Implementation:**
337
+ ```python
338
+ @app.post("/v1/chat")
339
+ async def chat_endpoint(request: dict):
340
+ # Your endpoint logic here
341
+ response_data = {
342
+ "output": "Hello! This is a response from the chat endpoint.",
343
+ "usage": {
344
+ "input_tokens": 150, # Tokens in the request
345
+ "output_tokens": 50, # Tokens in the response
346
+ "total_tokens": 200,
347
+ },
348
+ }
349
+ return JSONResponse(content=response_data)
350
+ ```
351
+
352
+ **Response (with settlement info):**
353
+ ```json
354
+ {
355
+ "output": "Hello! This is a response from the chat endpoint.",
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
+ },
366
+ "atp_settlement": {
367
+ "status": "paid",
368
+ "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
+ "payment": {
381
+ "total_amount_lamports": 300000,
382
+ "total_amount_sol": 0.0003,
383
+ "total_amount_usd": 0.003,
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
+ }
396
+ }
397
+ }
398
+ }
399
+ ```
400
+
401
+ ### Supported Usage Formats
402
+
403
+ The middleware automatically detects and parses usage data from multiple API formats:
404
+
405
+ - **OpenAI**: `prompt_tokens`, `completion_tokens`, `total_tokens`
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.
411
+
412
+ The middleware searches for usage data in this order:
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.)
416
+
417
+ ### Payment Flow
418
+
419
+ ```mermaid
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
438
+ ```
439
+
440
+ ### Payment Split Logic
441
+
442
+ The middleware automatically splits payments:
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
458
+
459
+ You can layer your own API key handling on top of the middleware:
460
+
461
+ ```python
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
+ }
466
+
467
+ def get_wallet_from_api_key(api_key: str = Header(..., alias="x-api-key")) -> str:
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]
472
+
473
+ # Use a custom middleware to inject wallet key from API key
474
+ # before the ATP middleware processes the request
475
+ ```
476
+
477
+ ### When to Use Middleware vs. Main Protocol
478
+
479
+ **Use the Middleware when:**
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
484
+
485
+ **Use the Main Protocol when:**
486
+ - You want explicit payment approval (402 challenge)
487
+ - You need to hold results until payment is confirmed
488
+ - You want a two-step verification process
489
+ - You're building a pay-to-unlock system
490
+
491
+ See `examples/middleware_usage_example.py` for a complete working example.
492
+