Skip to content

Conversation

@CarsonRoscoe
Copy link
Contributor

@CarsonRoscoe CarsonRoscoe commented Dec 22, 2025

Description

  • Moved the original Python SDK to /python/legacy
  • Added a new Python SDK under /python/x402
  • Implemented the EVM mechanism
  • Implement fastapi & flask middleware
  • Implemented httpx and request clients
  • Added to e2e tests

TODO for Typescript/Go Parity:

  • Add Solana mechanism
  • Add extensions & implement bazaar
  • Add e2e Python facilitator
  • Add Python facilitator example
  • Add Python middleware examples (fastapi & flask)
  • Add Python client examples (httpx & requests)
  • Code reviews (this is just the initial draft)

Tests

Screenshot 2025-12-22 at 7 53 43 AM

Checklist

  • I have formatted and linted my code
  • All new and existing tests pass
  • My commits are signed (required for merge) -- you may need to rebase if you initially pushed unsigned commits

@cb-heimdall
Copy link

cb-heimdall commented Dec 22, 2025

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

@vercel
Copy link

vercel bot commented Dec 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
x402 Ready Ready Preview, Comment Jan 16, 2026 4:30pm

Request Review

@phdargen
Copy link
Contributor

phdargen commented Dec 22, 2025

Awesome, thanks a lot for putting this out @CarsonRoscoe!

To everyone interested in contributing, please FIRST write a comment here with what you'd like to work on in order to avoid any duplicate work. I will coordinate and update the TODO below with who is working on what.

To simplify review, please open one PR per TODO item and try to keep changes strictly related to that to avoid merge conflicts.

TODO:

@phdargen phdargen self-assigned this Dec 22, 2025
@1bcMax
Copy link
Contributor

1bcMax commented Dec 22, 2025

TODO:

-[ ] Add Solana mechanism -[ ] Add extensions & implement bazaar -[ ] Add e2e Python facilitator -[ ] Update e2e tests for Solana support in clients, servers, & facilitators -[ ] Add Python facilitator example -[ ] Add Python middleware examples (fastapi & flask): @Ilevk adding fastapi example -[ ] Add Python client examples (httpx & requests)

Awesome, thanks a lot for putting this out @CarsonRoscoe!

To everyone interested in contributing, please FIRST write a comment here with what you'd like to work on in order to avoid any duplicate work. I will coordinate and update the TODO below with who is working on what.

To simplify review, please open one PR per TODO item and try to keep changes strictly related to that to avoid merge conflicts.

TODO:

-[ ] Add Solana mechanism
-[ ] Add extensions & implement bazaar
-[ ] Add e2e Python facilitator
-[ ] Update e2e tests for Solana support in clients, servers, & facilitators
-[X] Add Python facilitator example (@bc1max adding facilitator example)
-[ ] Add Python middleware examples (fastapi & flask): @Ilevk adding fastapi example
-[X ] Add Python client examples (httpx & requests)(@bc1max adding Python client example)

I will work on Python facilitator example and Python client examples (httpx & requests)

Please let me know if you are okay with it @CarsonRoscoe

@phdargen
Copy link
Contributor

Hi @1bcMax, thanks a lot for for offering your help! Let's start with one python client example (httpx) and then go from there. Updated the TODO list accordingly

@Cybercentry
Copy link
Contributor

Happy to review the code and examples for security issues, including both manual checks and static analysis. Please let me know if you’d like me to take a look!

@Ilevk
Copy link

Ilevk commented Dec 27, 2025

Awesome, thanks a lot for putting this out @CarsonRoscoe!

To everyone interested in contributing, please FIRST write a comment here with what you'd like to work on in order to avoid > any duplicate work. I will coordinate and update the TODO below with who is working on what.

To simplify review, please open one PR per TODO item and try to keep changes strictly related to that to avoid merge conflicts.

Thanks @phdargen I'd love to contribute the examples.

TODO:

  • Add Python middleware examples (fastapi & flask): @Ilevk adding fastapi example
  • Add advanced/custom Python middleware examples (fastapi or flask): @Ilevk
  • Fix x402HTTPAdapter retry logic: @Ilevk

Ilevk added a commit to Daehan-Base/awesome-x402-on-base that referenced this pull request Dec 27, 2025
Add link to in-progress Python v2 SDK work (coinbase/x402#841)
in Python documentation files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ilevk added a commit to Daehan-Base/awesome-x402-on-base that referenced this pull request Dec 27, 2025
* refactor: reorganize directory structure to language-first pattern

Reorganize examples/ and docs/korean/ directories to match
the official x402 repository structure (language/version/type).

Changes:
- examples/v1/ → examples/python/v1/
- examples/v2/ → examples/python/v2/
- docs/korean/v1/ → docs/korean/python/v1/
- docs/korean/v2/ → docs/korean/python/v2/
- Remove python- prefix from example doc filenames
- Update all README path references
- Update CLAUDE.md directory structure section

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: convert external paths to official GitHub links

- Replace local external/x402/ paths with GitHub repository links
- Updated files:
  - examples/README.md, README.en.md
  - examples/python/v2/README.md, README.en.md
  - docs/korean/python/v1/README.md, README.en.md
  - docs/korean/python/v2/README.md, README.en.md
  - docs/korean/getting_started.ko.md
  - docs/korean/python/v1/examples/*.ko.md (4 files)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: docs language-first structure with TypeScript versioning

- Move docs/korean/ to docs/ (language-agnostic root)
- Add TypeScript v1/v2 versioning structure
- Create TypeScript index README and v1 placeholder
- Convert external paths to GitHub links in TypeScript docs
- Fix Python v1 internal links (remove python- prefix)
- Fix Python v1 examples relative paths for new structure
- Add TypeScript documentation links to docs/README.md

Directory structure:
docs/
├── python/v1/examples/  (Python v1 Legacy)
├── python/v2/           (Python v2)
├── typescript/v1/       (placeholder)
├── typescript/v2/       (TypeScript v2 examples)
└── getting_started.ko.md, x402-v2-specification.ko.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: update broken links in getting_started.ko.md after restructure

- Update Python example paths: ./v1/examples/python-* → ./python/v1/examples/*
- Fix resources relative path: ../../resources/ → ../resources/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: add footer navigation to TypeScript v2 docs and update README structure

- Add footer navigation to all TypeScript v2 example README files
- Update main README directory structure diagram to reflect current layout
- Fix broken links in README.md and README.en.md (docs/korean/ → docs/)
- Update example links to new language-first structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: resolve 4-persona review issues (Phase 1-3)

Critical fixes:
- Fix 4 broken links in x402-v2-specification.ko.md (wrong path + filename)
- Add TypeScript v2 Quick Start section to root README

High priority fixes:
- Create docs/python/README.md and README.en.md
- Create docs/typescript/v2/fullstack/README.md and README.en.md
- Fix docs/README.md relative path (../../README.md → ../README.md)
- Fix korean-community broken link in getting_started.ko.md

Medium priority fixes:
- Fix Python v1 examples v2-spec links (4 files)
- Add English footer navigation to TypeScript v2 docs (15 files)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: resolve broken links from final review

- Fix LICENSE links in x402-v2-specification.ko.md and getting_started.ko.md
  (../../LICENSE → ../LICENSE)
- Fix v2-spec links in python/v2/README.md and README.en.md
  (../x402-v2-specification.ko.md → ../../x402-v2-specification.ko.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: restructure Python v1 docs from examples/ to feature-based dirs

- Move examples/*.ko.md to clients/, servers/, discovery/ directories
- Rename all files to README.md for consistency
- Update all internal links across 14 files to match new structure
- Fix broken links in root READMEs, docs/, and external/ directories

New structure:
  docs/python/v1/
  ├── clients/requests/README.md
  ├── clients/httpx/README.md
  ├── servers/fastapi/README.md
  └── discovery/README.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: add language toggle linking to official x402 examples

Add language toggle at the top of Python v1 docs with English links
pointing to official coinbase/x402 repository examples instead of
maintaining separate English translations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: update repository structure to reflect Python v1 reorganization

Update docs/python/v1/ structure in both README files to show
new feature-based directory layout (clients/, servers/, discovery/).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: reorganize external/ README with language versions

- Update README.md as Korean default
- Add README.en.md for English version
- Remove redundant README.ko.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: simplify docs paths and rename getting_started

- Remove 'korean' from docs path (docs/korean/ → docs/)
- Rename getting_started.ko.md to getting_started.md
- Update all references across 14 files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add official code links to TypeScript examples table

Add links to official coinbase/x402 repository for all TypeScript v2
examples (axios, fetch, express, hono, next, miniapp, mcp).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: rename x402-v2-specification.ko.md to .md

Remove '.ko' suffix from v2 specification filename and update
all references across 15 files for consistency.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: update v1/examples/ references to new v1/ structure

Update paths across 8 files to reflect the new directory structure:
- docs/python/v1/examples/ → docs/python/v1/ (clients/, servers/, discovery/)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add English README.en.md for Python v1 examples

- Create English versions for 4 Python v1 docs:
  - clients/requests/README.en.md
  - clients/httpx/README.en.md
  - servers/fastapi/README.en.md
  - discovery/README.en.md
- Update Korean READMEs with correct language toggle links
- Fix footer navigation paths (../ → ../../ for nested dirs)
- Fix v2-spec relative paths

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add Python v2 SDK PR #841 reference

Add link to in-progress Python v2 SDK work (coinbase/x402#841)
in Python documentation files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
@Darjiro
Copy link

Darjiro commented Dec 27, 2025

Hi guys, I just opened a PR. It's just a specific example for the CDP facilitator on Mainnet to serve as a workaround until cdp-sdk is updated. #874

@1bcMax
Copy link
Contributor

1bcMax commented Jan 11, 2026

Awesome, thanks a lot for putting this out @CarsonRoscoe!

To everyone interested in contributing, please FIRST write a comment here with what you'd like to work on in order to avoid any duplicate work. I will coordinate and update the TODO below with who is working on what.

To simplify review, please open one PR per TODO item and try to keep changes strictly related to that to avoid merge conflicts.

TODO:

  • Add Solana mechanism: 904 by @phdargen
  • Add extensions & implement bazaar: 929 by @phdargen
  • Add e2e Python facilitator
  • Update e2e tests for Solana support in clients, servers, & facilitators: 904 by @phdargen
  • Add Python facilitator example
  • Add basic Python middleware examples (fastapi & flask): 879 by @Ilevk
  • Add advanced/custom Python middleware examples (fastapi or flask): @Ilevk
  • Add basic Python client examples (httpx & requests): 857 by @1bcMax
  • Add advanced/custom Python client examples (httpx or requests) @1bcMax
  • Fix x402HTTPAdapter retry logic: @Ilevk
  • Async support for dynamic route config: 900 by @shuhei0866
  • Make framework/client deps optional extras: 901 by @vvsotnikov
  • Add v2 paywall support

@phdargen Since I had finished "Add basic Python client examples (httpx & requests)"[857], I will finish "Add advanced/custom Python client examples (httpx or requests)" later today.

@1bcMax 1bcMax mentioned this pull request Jan 11, 2026
6 tasks
@shuhei0866
Copy link

Quick update on my TODO item:

Async support for dynamic route config — PR #900 has been updated with the dual class design (x402HTTPResourceServer / x402HTTPResourceServerSync) based on @CarsonRoscoe's feedback. Ready for review!

* Add advanced Python client examples

Implements 5 advanced patterns demonstrating x402 SDK v2 features:
- hooks.py: Payment lifecycle hooks (before, after, failure)
- preferred_network.py: Custom network preference selector
- builder_pattern.py: Network-specific registration with wildcards
- error_recovery.py: Error classification and recovery strategies
- custom_transport.py: Custom httpx transport with retry/timing

Includes:
- CLI entry point (index.py) for running examples
- Comprehensive test suite (40 unit tests)
- E2E integration tests
- README documentation

All tests passing.

* Remove tests and examples beyond TypeScript SDK parity

Address PR review feedback:
- Remove tests directory (tests belong in SDK, not examples)
- Remove custom_transport.py (runtime error, beyond TS parity)
- Remove error_recovery.py (duplicate of hooks.py, beyond TS parity)
- Update index.py, README.md, pyproject.toml accordingly

* Address PR feedback: add SVM support and use optional deps

- Update pyproject.toml to use x402[evm,svm,httpx] instead of
  listing dependencies separately
- Add Solana/SVM network examples to preferred_network.py
- Support both EVM and SVM signers for cross-chain flexibility
- Update .env-local with SOLANA_PRIVATE_KEY option
* add facilitator example

* improve svm signer

* add description to DiscoveredResource

* add facilitator e2e
Comment on lines +231 to +239
return {
"success": False,
"errorReason": str(e).replace("Settlement aborted: ", ""),
"network": request.paymentPayload.get("accepted", {}).get(
"network", "unknown"
),
"transaction": "",
"payer": None,
}

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 2 days ago

General fix: avoid returning raw exception messages to the client. Log the detailed error (including stack trace) on the server, and send back a generic, user-safe message. When you do want to expose a reason, derive it from a controlled source (e.g., well-defined error codes/messages), not from str(e).

Best concrete fix here:

  • In the /settle handler, keep logging the full exception for diagnostics, but:
    • For the "aborted" hook path, do not use str(e) directly. Return a generic error message like "Settlement aborted" (or a controlled message), optionally stripping the prefix only if you are sure it’s safe. Given the CodeQL warning, the simplest safe approach is to avoid using the exception text entirely in the response.
    • For the generic error path (raise HTTPException(...)), replace detail=str(e) with a generic message like "Internal server error during settlement".
  • To improve server-side debugging, we can add stack-trace logging via traceback.format_exc() in the except block.
  • All changes are confined to e2e/facilitators/python/main.py inside the shown code region. We can add a standard-library import (traceback) at the top of the file.

Concretely:

  1. Add import traceback alongside the other imports.
  2. In the except Exception as e: in settle:
    • Replace print(f"Settle error: {e}") with something like print(f"Settle error: {e}\n{traceback.format_exc()}") to log more detail but keep it server-side.
    • In the "aborted" branch, stop passing through str(e); instead, use a generic, controlled message (e.g., "Settlement aborted").
    • In the final HTTPException, replace detail=str(e) with a generic message (e.g., "Internal server error during settlement").
  3. The /supported endpoint is already only sending a generic HTTP 500 message, but it currently uses detail=str(e) as well; however, CodeQL’s highlighted flow is about the /settle response body. To keep the fix focused on the reported issue, we will not alter /supported unless required.
Suggested changeset 1
e2e/facilitators/python/main.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/e2e/facilitators/python/main.py b/e2e/facilitators/python/main.py
--- a/e2e/facilitators/python/main.py
+++ b/e2e/facilitators/python/main.py
@@ -21,6 +21,7 @@
 from fastapi import FastAPI, HTTPException
 from pydantic import BaseModel
 from solders.keypair import Keypair
+import traceback
 
 from x402 import x402Facilitator
 from x402.extensions.bazaar import DiscoveredResource, extract_discovery_info
@@ -223,14 +224,16 @@
             "errorReason": response.error_reason,
         }
     except Exception as e:
-        print(f"Settle error: {e}")
+        # Log full error details server-side, including stack trace
+        print(f"Settle error: {e}\n{traceback.format_exc()}")
 
         # Check if this was an abort from hook
-        if "aborted" in str(e).lower() or "Settlement aborted" in str(e):
-            # Return a proper SettleResponse instead of 500 error
+        if "aborted" in str(e).lower() or "settlement aborted" in str(e).lower():
+            # Return a proper SettleResponse instead of 500 error,
+            # but avoid exposing internal exception details.
             return {
                 "success": False,
-                "errorReason": str(e).replace("Settlement aborted: ", ""),
+                "errorReason": "Settlement aborted",
                 "network": request.paymentPayload.get("accepted", {}).get(
                     "network", "unknown"
                 ),
@@ -238,7 +237,11 @@
                 "payer": None,
             }
 
-        raise HTTPException(status_code=500, detail=str(e))
+        # For all other errors, return a generic internal error message
+        raise HTTPException(
+            status_code=500,
+            detail="Internal server error during settlement",
+        )
 
 
 @app.get("/supported")
EOF
@@ -21,6 +21,7 @@
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from solders.keypair import Keypair
import traceback

from x402 import x402Facilitator
from x402.extensions.bazaar import DiscoveredResource, extract_discovery_info
@@ -223,14 +224,16 @@
"errorReason": response.error_reason,
}
except Exception as e:
print(f"Settle error: {e}")
# Log full error details server-side, including stack trace
print(f"Settle error: {e}\n{traceback.format_exc()}")

# Check if this was an abort from hook
if "aborted" in str(e).lower() or "Settlement aborted" in str(e):
# Return a proper SettleResponse instead of 500 error
if "aborted" in str(e).lower() or "settlement aborted" in str(e).lower():
# Return a proper SettleResponse instead of 500 error,
# but avoid exposing internal exception details.
return {
"success": False,
"errorReason": str(e).replace("Settlement aborted: ", ""),
"errorReason": "Settlement aborted",
"network": request.paymentPayload.get("accepted", {}).get(
"network", "unknown"
),
@@ -238,7 +237,11 @@
"payer": None,
}

raise HTTPException(status_code=500, detail=str(e))
# For all other errors, return a generic internal error message
raise HTTPException(
status_code=500,
detail="Internal server error during settlement",
)


@app.get("/supported")
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines 164 to 171
return {
"success": False,
"errorReason": str(e),
"network": request.paymentPayload.get("accepted", {}).get(
"network", "unknown"
),
"transaction": "",
}

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 2 days ago

In general, to fix information exposure through exceptions, avoid returning raw exception messages or stack traces to clients. Instead, log the full exception server-side (optionally with stack trace) and return a generic, user-safe error message. For business-logic errors where the client needs specific feedback, define controlled, sanitized messages or error codes rather than using arbitrary exception text.

For this file, the best minimal fix without changing functionality structure is:

  • In the settle endpoint:
    • Keep logging the error server-side.
    • For the “aborted” case, return a response with success: False and the same network/transaction fields, but replace errorReason: str(e) with a generic or at least non-technical message such as "Payment aborted" or "Payment aborted due to a client-side condition.".
    • For non-aborted errors, keep raising HTTPException(status_code=500, ...) but change detail=str(e) to a generic string such as "Internal server error" so exception details are not leaked.
  • In the supported endpoint:
    • Keep logging the error.
    • Change HTTPException(status_code=500, detail=str(e)) to use a generic message like "Internal server error".

No new imports are strictly necessary beyond what is already present; we can continue to use print for minimal logging as in the existing code. If this project later adopts a logging framework, these print calls can be replaced, but we won’t assume that here.

Concretely:

  • Edit the except block in settle (lines 185–197) to:
    • Use a generic errorReason string in the aborted branch.
    • Use a generic detail in HTTPException.
  • Edit the except block in supported (lines 223–225) to use a generic detail.
Suggested changeset 1
examples/python/facilitator/main.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/examples/python/facilitator/main.py b/examples/python/facilitator/main.py
--- a/examples/python/facilitator/main.py
+++ b/examples/python/facilitator/main.py
@@ -189,12 +189,12 @@
         if "aborted" in str(e).lower():
             return {
                 "success": False,
-                "errorReason": str(e),
+                "errorReason": "Payment aborted.",
                 "network": request.paymentPayload.get("accepted", {}).get("network", "unknown"),
                 "transaction": "",
             }
 
-        raise HTTPException(status_code=500, detail=str(e))
+        raise HTTPException(status_code=500, detail="Internal server error")
 
 
 @app.get("/supported")
@@ -222,7 +218,7 @@
         }
     except Exception as e:
         print(f"Supported error: {e}")
-        raise HTTPException(status_code=500, detail=str(e))
+        raise HTTPException(status_code=500, detail="Internal server error")
 
 
 @app.get("/health")
EOF
@@ -189,12 +189,12 @@
if "aborted" in str(e).lower():
return {
"success": False,
"errorReason": str(e),
"errorReason": "Payment aborted.",
"network": request.paymentPayload.get("accepted", {}).get("network", "unknown"),
"transaction": "",
}

raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Internal server error")


@app.get("/supported")
@@ -222,7 +218,7 @@
}
except Exception as e:
print(f"Supported error: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Internal server error")


@app.get("/health")
Copilot is powered by AI and may make mistakes. Always verify output.
Demonstrates manual x402 v2 payment flow without convenience wrappers.

Shows the 6-step process:
1. Initialize client and register payment schemes
2. Make initial request, receive 402
3. Decode PAYMENT-REQUIRED header
4. Create signed payment payload
5. Retry with PAYMENT-SIGNATURE header
6. Handle success/failure response

Useful for integrating with non-standard HTTP libraries or implementing
custom retry logic.
* feat(http): implement dual class design for sync/async support

- Add x402HTTPResourceServer (async) for FastAPI/Starlette
- Add x402HTTPResourceServerSync (sync) for Flask/Django
- Share common logic via _x402HTTPServerBase
- Remove dynamic description/resource (keep only dynamic price/payTo)
- Update Flask middleware to use sync server directly
- Integrate with enrich_extensions for bazaar support
- Add per-route hook_timeout_seconds configuration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(types): add missing Awaitable import and fix test import sorting

- Add Awaitable import to types.py for DynamicPayTo/DynamicPrice type hints
- Fix import block sorting in test_async_hooks.py and test_core.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: simplify API by removing unused types and making timeout opt-in

Address reviewer feedback from @phdargen:
- Remove SyncDynamicPayTo/SyncDynamicPrice (unused types that would require SyncPaymentOption to be useful)
- Change hook_timeout_seconds default to None (opt-in, matching TS/Go parity)
- Export x402HTTPResourceServerSync from http/__init__.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
)

* make create_facilitator_config work with both V1 and V2

* fix lint
* feat - add pyproject.toml, uv.lock for advanced example

* feat - add bazaar extension

* feat - add hooks

* feat - add x402 extensions to pyproject.toml

* feat - add dynamic pricing feature

* feat - add dynamic pay-to and custom money parser features

* docs - add README for advanced server example

* style - apply lint

* chore - add comments for bazaar extension code
* fix: fix consecutive payment bug in x402HTTPAdapter

- Replace instance-level _is_retry flag with per-request header
  to prevent state leakage between consecutive 402 requests.

* tests - add test case for consecutive payment with x402HTTPAdapter

* style - apply lint
* add dual sync/async classes for server/client/facilitator

* update integration/e2e tests

* add unit tests for core, http and implement wrapHttpxWithPaymentFromConfig/wrapRequestsWithPayment

* refactor core server/client/facilitator

* refactor x402_http_server/facilitator_client/x402_http_client

* update exmamples

* add utility function that takes care of html-safe escaping

* add sdk readmes

* add retry unit tests to httpx client
Comment on lines +237 to +240
content={
"error": "Payment Processing Error",
"message": str(e),
},

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 2 days ago

In general, the fix is to avoid returning raw exception details to the client. Instead, log the exception on the server (ideally with stack trace) and return a generic, non-sensitive error message in the HTTP response body.

For this specific code, the best minimal fix without changing existing functionality is:

  • Keep catching Exception to avoid breaking behavior.
  • Add server-side logging of the exception (including stack trace), using the standard library logging module.
  • Replace the "message": str(e) field in the JSON response with a generic, stable string that does not depend on the exception content (for example, "An internal error occurred while processing payment.").
  • Optionally, keep the existing "error": "Payment Processing Error" field for clients that expect it.

Concretely:

  1. At the top of examples/python/servers/custom/main.py, add import logging and configure a module-level logger (e.g., logger = logging.getLogger(__name__)). If you want more explicit logs without altering global configuration, you can rely on default logging setup; this change does not break existing behavior.

  2. In the except Exception as e: block starting at line 233, replace the print(f"❌ Payment processing error: {e}") call with a logging call like logger.exception("Payment processing error"), which logs the message and stack trace.

  3. In the same block, change the JSONResponse content to not include str(e). For example:

content={
    "error": "Payment Processing Error",
    "message": "An internal error occurred while processing payment.",
}

This preserves the external API shape (error and message fields) while eliminating exposure of exception details.

Suggested changeset 1
examples/python/servers/custom/main.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/examples/python/servers/custom/main.py b/examples/python/servers/custom/main.py
--- a/examples/python/servers/custom/main.py
+++ b/examples/python/servers/custom/main.py
@@ -23,6 +23,7 @@
 import sys
 from dataclasses import dataclass, field
 
+import logging
 from dotenv import load_dotenv
 from fastapi import FastAPI, Request, Response
 from fastapi.responses import JSONResponse
@@ -32,6 +33,8 @@
 from x402.schemas import Network, PaymentPayload, PaymentRequirements, ResourceConfig
 from x402.server import x402ResourceServer
 
+logger = logging.getLogger(__name__)
+
 load_dotenv()
 
 # Config
@@ -231,12 +234,12 @@
         return response
 
     except Exception as e:
-        print(f"❌ Payment processing error: {e}")
+        logger.exception("Payment processing error")
         return JSONResponse(
             status_code=500,
             content={
                 "error": "Payment Processing Error",
-                "message": str(e),
+                "message": "An internal error occurred while processing payment.",
             },
         )
 
EOF
@@ -23,6 +23,7 @@
import sys
from dataclasses import dataclass, field

import logging
from dotenv import load_dotenv
from fastapi import FastAPI, Request, Response
from fastapi.responses import JSONResponse
@@ -32,6 +33,8 @@
from x402.schemas import Network, PaymentPayload, PaymentRequirements, ResourceConfig
from x402.server import x402ResourceServer

logger = logging.getLogger(__name__)

load_dotenv()

# Config
@@ -231,12 +234,12 @@
return response

except Exception as e:
print(f"❌ Payment processing error: {e}")
logger.exception("Payment processing error")
return JSONResponse(
status_code=500,
content={
"error": "Payment Processing Error",
"message": str(e),
"message": "An internal error occurred while processing payment.",
},
)

Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci examples Changes to examples legacy Changes to legacy sdk or examples python sdk Changes to core v2 packages typescript

Development

Successfully merging this pull request may close these issues.