uvd-x402-sdk 0.2.1__py3-none-any.whl → 0.2.3__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.
- uvd_x402_sdk/__init__.py +169 -169
- uvd_x402_sdk/client.py +527 -527
- uvd_x402_sdk/config.py +248 -248
- uvd_x402_sdk/decorators.py +325 -325
- uvd_x402_sdk/exceptions.py +254 -254
- uvd_x402_sdk/integrations/__init__.py +74 -74
- uvd_x402_sdk/integrations/django_integration.py +237 -237
- uvd_x402_sdk/integrations/fastapi_integration.py +330 -330
- uvd_x402_sdk/integrations/flask_integration.py +259 -259
- uvd_x402_sdk/integrations/lambda_integration.py +320 -320
- uvd_x402_sdk/models.py +397 -397
- uvd_x402_sdk/networks/__init__.py +54 -54
- uvd_x402_sdk/networks/base.py +347 -347
- uvd_x402_sdk/networks/evm.py +215 -215
- uvd_x402_sdk/networks/near.py +397 -397
- uvd_x402_sdk/networks/solana.py +282 -269
- uvd_x402_sdk/networks/stellar.py +129 -129
- uvd_x402_sdk/response.py +439 -439
- {uvd_x402_sdk-0.2.1.dist-info → uvd_x402_sdk-0.2.3.dist-info}/LICENSE +21 -21
- {uvd_x402_sdk-0.2.1.dist-info → uvd_x402_sdk-0.2.3.dist-info}/METADATA +814 -778
- uvd_x402_sdk-0.2.3.dist-info/RECORD +23 -0
- uvd_x402_sdk-0.2.1.dist-info/RECORD +0 -23
- {uvd_x402_sdk-0.2.1.dist-info → uvd_x402_sdk-0.2.3.dist-info}/WHEEL +0 -0
- {uvd_x402_sdk-0.2.1.dist-info → uvd_x402_sdk-0.2.3.dist-info}/top_level.txt +0 -0
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Django integration for x402 payments.
|
|
3
|
-
|
|
4
|
-
Provides:
|
|
5
|
-
- DjangoX402Middleware: Middleware for protecting views
|
|
6
|
-
- django_require_payment: Decorator for view functions
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from decimal import Decimal
|
|
10
|
-
from functools import wraps
|
|
11
|
-
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
|
|
12
|
-
import json
|
|
13
|
-
|
|
14
|
-
try:
|
|
15
|
-
from django.http import JsonResponse, HttpRequest, HttpResponse
|
|
16
|
-
from django.conf import settings
|
|
17
|
-
except ImportError:
|
|
18
|
-
raise ImportError(
|
|
19
|
-
"Django is required for Django integration. "
|
|
20
|
-
"Install with: pip install uvd-x402-sdk[django]"
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
from uvd_x402_sdk.client import X402Client
|
|
24
|
-
from uvd_x402_sdk.config import X402Config
|
|
25
|
-
from uvd_x402_sdk.exceptions import X402Error
|
|
26
|
-
from uvd_x402_sdk.models import PaymentResult
|
|
27
|
-
from uvd_x402_sdk.response import create_402_response, create_402_headers
|
|
28
|
-
|
|
29
|
-
F = TypeVar("F", bound=Callable[..., Any])
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _get_config_from_settings() -> X402Config:
|
|
33
|
-
"""Get x402 configuration from Django settings."""
|
|
34
|
-
return X402Config(
|
|
35
|
-
facilitator_url=getattr(
|
|
36
|
-
settings,
|
|
37
|
-
"X402_FACILITATOR_URL",
|
|
38
|
-
"https://facilitator.ultravioletadao.xyz",
|
|
39
|
-
),
|
|
40
|
-
recipient_evm=getattr(settings, "X402_RECIPIENT_EVM", ""),
|
|
41
|
-
recipient_solana=getattr(settings, "X402_RECIPIENT_SOLANA", ""),
|
|
42
|
-
recipient_near=getattr(settings, "X402_RECIPIENT_NEAR", ""),
|
|
43
|
-
recipient_stellar=getattr(settings, "X402_RECIPIENT_STELLAR", ""),
|
|
44
|
-
facilitator_solana=getattr(
|
|
45
|
-
settings,
|
|
46
|
-
"X402_FACILITATOR_SOLANA",
|
|
47
|
-
"F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq",
|
|
48
|
-
),
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class DjangoX402Middleware:
|
|
53
|
-
"""
|
|
54
|
-
Django middleware for x402 payment protection.
|
|
55
|
-
|
|
56
|
-
Configure protected paths in Django settings:
|
|
57
|
-
|
|
58
|
-
# settings.py
|
|
59
|
-
X402_RECIPIENT_EVM = "0xYourWallet..."
|
|
60
|
-
X402_PROTECTED_PATHS = {
|
|
61
|
-
"/api/premium/": "5.00",
|
|
62
|
-
"/api/basic/": "1.00",
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
Example:
|
|
66
|
-
# settings.py
|
|
67
|
-
MIDDLEWARE = [
|
|
68
|
-
...
|
|
69
|
-
'uvd_x402_sdk.integrations.django_integration.DjangoX402Middleware',
|
|
70
|
-
]
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]) -> None:
|
|
74
|
-
self.get_response = get_response
|
|
75
|
-
self._config = _get_config_from_settings()
|
|
76
|
-
self._client = X402Client(config=self._config)
|
|
77
|
-
self._protected_paths: Dict[str, Decimal] = {}
|
|
78
|
-
|
|
79
|
-
# Load protected paths from settings
|
|
80
|
-
paths_setting = getattr(settings, "X402_PROTECTED_PATHS", {})
|
|
81
|
-
for path, amount in paths_setting.items():
|
|
82
|
-
self._protected_paths[path] = Decimal(str(amount))
|
|
83
|
-
|
|
84
|
-
def __call__(self, request: HttpRequest) -> HttpResponse:
|
|
85
|
-
# Check if path is protected
|
|
86
|
-
path = request.path
|
|
87
|
-
|
|
88
|
-
# Try exact match first, then prefix match
|
|
89
|
-
required_amount = None
|
|
90
|
-
for protected_path, amount in self._protected_paths.items():
|
|
91
|
-
if path == protected_path or path.startswith(protected_path):
|
|
92
|
-
required_amount = amount
|
|
93
|
-
break
|
|
94
|
-
|
|
95
|
-
if required_amount is None:
|
|
96
|
-
return self.get_response(request)
|
|
97
|
-
|
|
98
|
-
# Get payment header (Django uses HTTP_X_PAYMENT format)
|
|
99
|
-
payment_header = request.META.get("HTTP_X_PAYMENT")
|
|
100
|
-
|
|
101
|
-
if not payment_header:
|
|
102
|
-
response_body = create_402_response(
|
|
103
|
-
amount_usd=required_amount,
|
|
104
|
-
config=self._config,
|
|
105
|
-
)
|
|
106
|
-
response = JsonResponse(response_body, status=402)
|
|
107
|
-
for key, value in create_402_headers().items():
|
|
108
|
-
response[key] = value
|
|
109
|
-
return response
|
|
110
|
-
|
|
111
|
-
try:
|
|
112
|
-
result = self._client.process_payment(
|
|
113
|
-
x_payment_header=payment_header,
|
|
114
|
-
expected_amount_usd=required_amount,
|
|
115
|
-
)
|
|
116
|
-
# Store result on request for view access
|
|
117
|
-
request.payment_result = result # type: ignore
|
|
118
|
-
return self.get_response(request)
|
|
119
|
-
|
|
120
|
-
except X402Error as e:
|
|
121
|
-
response = JsonResponse(e.to_dict(), status=402)
|
|
122
|
-
for key, value in create_402_headers().items():
|
|
123
|
-
response[key] = value
|
|
124
|
-
return response
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def django_require_payment(
|
|
128
|
-
amount_usd: Union[Decimal, float, str],
|
|
129
|
-
config: Optional[X402Config] = None,
|
|
130
|
-
message: Optional[str] = None,
|
|
131
|
-
) -> Callable[[F], F]:
|
|
132
|
-
"""
|
|
133
|
-
Decorator that requires payment for a Django view.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
amount_usd: Required payment amount in USD
|
|
137
|
-
config: X402Config (uses Django settings if not provided)
|
|
138
|
-
message: Custom message for 402 response
|
|
139
|
-
|
|
140
|
-
Example:
|
|
141
|
-
>>> from uvd_x402_sdk.integrations import django_require_payment
|
|
142
|
-
>>>
|
|
143
|
-
>>> @django_require_payment(amount_usd="1.00")
|
|
144
|
-
>>> def my_view(request):
|
|
145
|
-
... # Access payment result via request.payment_result
|
|
146
|
-
... return JsonResponse({"payer": request.payment_result.payer_address})
|
|
147
|
-
"""
|
|
148
|
-
required_amount = Decimal(str(amount_usd))
|
|
149
|
-
_config = config or _get_config_from_settings()
|
|
150
|
-
_client = X402Client(config=_config)
|
|
151
|
-
|
|
152
|
-
def decorator(func: F) -> F:
|
|
153
|
-
@wraps(func)
|
|
154
|
-
def wrapper(request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
|
155
|
-
# Get payment header
|
|
156
|
-
payment_header = request.META.get("HTTP_X_PAYMENT")
|
|
157
|
-
|
|
158
|
-
if not payment_header:
|
|
159
|
-
response_body = create_402_response(
|
|
160
|
-
amount_usd=required_amount,
|
|
161
|
-
config=_config,
|
|
162
|
-
message=message,
|
|
163
|
-
)
|
|
164
|
-
response = JsonResponse(response_body, status=402)
|
|
165
|
-
for key, value in create_402_headers().items():
|
|
166
|
-
response[key] = value
|
|
167
|
-
return response
|
|
168
|
-
|
|
169
|
-
try:
|
|
170
|
-
result = _client.process_payment(
|
|
171
|
-
x_payment_header=payment_header,
|
|
172
|
-
expected_amount_usd=required_amount,
|
|
173
|
-
)
|
|
174
|
-
# Store result on request
|
|
175
|
-
request.payment_result = result # type: ignore
|
|
176
|
-
return func(request, *args, **kwargs)
|
|
177
|
-
|
|
178
|
-
except X402Error as e:
|
|
179
|
-
response = JsonResponse(e.to_dict(), status=402)
|
|
180
|
-
for key, value in create_402_headers().items():
|
|
181
|
-
response[key] = value
|
|
182
|
-
return response
|
|
183
|
-
|
|
184
|
-
return wrapper # type: ignore
|
|
185
|
-
|
|
186
|
-
return decorator
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
class X402PaymentView:
|
|
190
|
-
"""
|
|
191
|
-
Mixin for Django class-based views requiring payment.
|
|
192
|
-
|
|
193
|
-
Example:
|
|
194
|
-
>>> from django.views import View
|
|
195
|
-
>>> from uvd_x402_sdk.integrations.django_integration import X402PaymentView
|
|
196
|
-
>>>
|
|
197
|
-
>>> class PremiumAPIView(X402PaymentView, View):
|
|
198
|
-
... x402_amount = Decimal("5.00")
|
|
199
|
-
...
|
|
200
|
-
... def get(self, request):
|
|
201
|
-
... return JsonResponse({"payer": request.payment_result.payer_address})
|
|
202
|
-
"""
|
|
203
|
-
|
|
204
|
-
x402_amount: Decimal = Decimal("1.00")
|
|
205
|
-
x402_message: Optional[str] = None
|
|
206
|
-
x402_config: Optional[X402Config] = None
|
|
207
|
-
|
|
208
|
-
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
|
209
|
-
config = self.x402_config or _get_config_from_settings()
|
|
210
|
-
client = X402Client(config=config)
|
|
211
|
-
|
|
212
|
-
payment_header = request.META.get("HTTP_X_PAYMENT")
|
|
213
|
-
|
|
214
|
-
if not payment_header:
|
|
215
|
-
response_body = create_402_response(
|
|
216
|
-
amount_usd=self.x402_amount,
|
|
217
|
-
config=config,
|
|
218
|
-
message=self.x402_message,
|
|
219
|
-
)
|
|
220
|
-
response = JsonResponse(response_body, status=402)
|
|
221
|
-
for key, value in create_402_headers().items():
|
|
222
|
-
response[key] = value
|
|
223
|
-
return response
|
|
224
|
-
|
|
225
|
-
try:
|
|
226
|
-
result = client.process_payment(
|
|
227
|
-
x_payment_header=payment_header,
|
|
228
|
-
expected_amount_usd=self.x402_amount,
|
|
229
|
-
)
|
|
230
|
-
request.payment_result = result # type: ignore
|
|
231
|
-
return super().dispatch(request, *args, **kwargs) # type: ignore
|
|
232
|
-
|
|
233
|
-
except X402Error as e:
|
|
234
|
-
response = JsonResponse(e.to_dict(), status=402)
|
|
235
|
-
for key, value in create_402_headers().items():
|
|
236
|
-
response[key] = value
|
|
237
|
-
return response
|
|
1
|
+
"""
|
|
2
|
+
Django integration for x402 payments.
|
|
3
|
+
|
|
4
|
+
Provides:
|
|
5
|
+
- DjangoX402Middleware: Middleware for protecting views
|
|
6
|
+
- django_require_payment: Decorator for view functions
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from decimal import Decimal
|
|
10
|
+
from functools import wraps
|
|
11
|
+
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from django.http import JsonResponse, HttpRequest, HttpResponse
|
|
16
|
+
from django.conf import settings
|
|
17
|
+
except ImportError:
|
|
18
|
+
raise ImportError(
|
|
19
|
+
"Django is required for Django integration. "
|
|
20
|
+
"Install with: pip install uvd-x402-sdk[django]"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from uvd_x402_sdk.client import X402Client
|
|
24
|
+
from uvd_x402_sdk.config import X402Config
|
|
25
|
+
from uvd_x402_sdk.exceptions import X402Error
|
|
26
|
+
from uvd_x402_sdk.models import PaymentResult
|
|
27
|
+
from uvd_x402_sdk.response import create_402_response, create_402_headers
|
|
28
|
+
|
|
29
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _get_config_from_settings() -> X402Config:
|
|
33
|
+
"""Get x402 configuration from Django settings."""
|
|
34
|
+
return X402Config(
|
|
35
|
+
facilitator_url=getattr(
|
|
36
|
+
settings,
|
|
37
|
+
"X402_FACILITATOR_URL",
|
|
38
|
+
"https://facilitator.ultravioletadao.xyz",
|
|
39
|
+
),
|
|
40
|
+
recipient_evm=getattr(settings, "X402_RECIPIENT_EVM", ""),
|
|
41
|
+
recipient_solana=getattr(settings, "X402_RECIPIENT_SOLANA", ""),
|
|
42
|
+
recipient_near=getattr(settings, "X402_RECIPIENT_NEAR", ""),
|
|
43
|
+
recipient_stellar=getattr(settings, "X402_RECIPIENT_STELLAR", ""),
|
|
44
|
+
facilitator_solana=getattr(
|
|
45
|
+
settings,
|
|
46
|
+
"X402_FACILITATOR_SOLANA",
|
|
47
|
+
"F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq",
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class DjangoX402Middleware:
|
|
53
|
+
"""
|
|
54
|
+
Django middleware for x402 payment protection.
|
|
55
|
+
|
|
56
|
+
Configure protected paths in Django settings:
|
|
57
|
+
|
|
58
|
+
# settings.py
|
|
59
|
+
X402_RECIPIENT_EVM = "0xYourWallet..."
|
|
60
|
+
X402_PROTECTED_PATHS = {
|
|
61
|
+
"/api/premium/": "5.00",
|
|
62
|
+
"/api/basic/": "1.00",
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
# settings.py
|
|
67
|
+
MIDDLEWARE = [
|
|
68
|
+
...
|
|
69
|
+
'uvd_x402_sdk.integrations.django_integration.DjangoX402Middleware',
|
|
70
|
+
]
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]) -> None:
|
|
74
|
+
self.get_response = get_response
|
|
75
|
+
self._config = _get_config_from_settings()
|
|
76
|
+
self._client = X402Client(config=self._config)
|
|
77
|
+
self._protected_paths: Dict[str, Decimal] = {}
|
|
78
|
+
|
|
79
|
+
# Load protected paths from settings
|
|
80
|
+
paths_setting = getattr(settings, "X402_PROTECTED_PATHS", {})
|
|
81
|
+
for path, amount in paths_setting.items():
|
|
82
|
+
self._protected_paths[path] = Decimal(str(amount))
|
|
83
|
+
|
|
84
|
+
def __call__(self, request: HttpRequest) -> HttpResponse:
|
|
85
|
+
# Check if path is protected
|
|
86
|
+
path = request.path
|
|
87
|
+
|
|
88
|
+
# Try exact match first, then prefix match
|
|
89
|
+
required_amount = None
|
|
90
|
+
for protected_path, amount in self._protected_paths.items():
|
|
91
|
+
if path == protected_path or path.startswith(protected_path):
|
|
92
|
+
required_amount = amount
|
|
93
|
+
break
|
|
94
|
+
|
|
95
|
+
if required_amount is None:
|
|
96
|
+
return self.get_response(request)
|
|
97
|
+
|
|
98
|
+
# Get payment header (Django uses HTTP_X_PAYMENT format)
|
|
99
|
+
payment_header = request.META.get("HTTP_X_PAYMENT")
|
|
100
|
+
|
|
101
|
+
if not payment_header:
|
|
102
|
+
response_body = create_402_response(
|
|
103
|
+
amount_usd=required_amount,
|
|
104
|
+
config=self._config,
|
|
105
|
+
)
|
|
106
|
+
response = JsonResponse(response_body, status=402)
|
|
107
|
+
for key, value in create_402_headers().items():
|
|
108
|
+
response[key] = value
|
|
109
|
+
return response
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
result = self._client.process_payment(
|
|
113
|
+
x_payment_header=payment_header,
|
|
114
|
+
expected_amount_usd=required_amount,
|
|
115
|
+
)
|
|
116
|
+
# Store result on request for view access
|
|
117
|
+
request.payment_result = result # type: ignore
|
|
118
|
+
return self.get_response(request)
|
|
119
|
+
|
|
120
|
+
except X402Error as e:
|
|
121
|
+
response = JsonResponse(e.to_dict(), status=402)
|
|
122
|
+
for key, value in create_402_headers().items():
|
|
123
|
+
response[key] = value
|
|
124
|
+
return response
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def django_require_payment(
|
|
128
|
+
amount_usd: Union[Decimal, float, str],
|
|
129
|
+
config: Optional[X402Config] = None,
|
|
130
|
+
message: Optional[str] = None,
|
|
131
|
+
) -> Callable[[F], F]:
|
|
132
|
+
"""
|
|
133
|
+
Decorator that requires payment for a Django view.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
amount_usd: Required payment amount in USD
|
|
137
|
+
config: X402Config (uses Django settings if not provided)
|
|
138
|
+
message: Custom message for 402 response
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
>>> from uvd_x402_sdk.integrations import django_require_payment
|
|
142
|
+
>>>
|
|
143
|
+
>>> @django_require_payment(amount_usd="1.00")
|
|
144
|
+
>>> def my_view(request):
|
|
145
|
+
... # Access payment result via request.payment_result
|
|
146
|
+
... return JsonResponse({"payer": request.payment_result.payer_address})
|
|
147
|
+
"""
|
|
148
|
+
required_amount = Decimal(str(amount_usd))
|
|
149
|
+
_config = config or _get_config_from_settings()
|
|
150
|
+
_client = X402Client(config=_config)
|
|
151
|
+
|
|
152
|
+
def decorator(func: F) -> F:
|
|
153
|
+
@wraps(func)
|
|
154
|
+
def wrapper(request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
|
155
|
+
# Get payment header
|
|
156
|
+
payment_header = request.META.get("HTTP_X_PAYMENT")
|
|
157
|
+
|
|
158
|
+
if not payment_header:
|
|
159
|
+
response_body = create_402_response(
|
|
160
|
+
amount_usd=required_amount,
|
|
161
|
+
config=_config,
|
|
162
|
+
message=message,
|
|
163
|
+
)
|
|
164
|
+
response = JsonResponse(response_body, status=402)
|
|
165
|
+
for key, value in create_402_headers().items():
|
|
166
|
+
response[key] = value
|
|
167
|
+
return response
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
result = _client.process_payment(
|
|
171
|
+
x_payment_header=payment_header,
|
|
172
|
+
expected_amount_usd=required_amount,
|
|
173
|
+
)
|
|
174
|
+
# Store result on request
|
|
175
|
+
request.payment_result = result # type: ignore
|
|
176
|
+
return func(request, *args, **kwargs)
|
|
177
|
+
|
|
178
|
+
except X402Error as e:
|
|
179
|
+
response = JsonResponse(e.to_dict(), status=402)
|
|
180
|
+
for key, value in create_402_headers().items():
|
|
181
|
+
response[key] = value
|
|
182
|
+
return response
|
|
183
|
+
|
|
184
|
+
return wrapper # type: ignore
|
|
185
|
+
|
|
186
|
+
return decorator
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class X402PaymentView:
|
|
190
|
+
"""
|
|
191
|
+
Mixin for Django class-based views requiring payment.
|
|
192
|
+
|
|
193
|
+
Example:
|
|
194
|
+
>>> from django.views import View
|
|
195
|
+
>>> from uvd_x402_sdk.integrations.django_integration import X402PaymentView
|
|
196
|
+
>>>
|
|
197
|
+
>>> class PremiumAPIView(X402PaymentView, View):
|
|
198
|
+
... x402_amount = Decimal("5.00")
|
|
199
|
+
...
|
|
200
|
+
... def get(self, request):
|
|
201
|
+
... return JsonResponse({"payer": request.payment_result.payer_address})
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
x402_amount: Decimal = Decimal("1.00")
|
|
205
|
+
x402_message: Optional[str] = None
|
|
206
|
+
x402_config: Optional[X402Config] = None
|
|
207
|
+
|
|
208
|
+
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
|
209
|
+
config = self.x402_config or _get_config_from_settings()
|
|
210
|
+
client = X402Client(config=config)
|
|
211
|
+
|
|
212
|
+
payment_header = request.META.get("HTTP_X_PAYMENT")
|
|
213
|
+
|
|
214
|
+
if not payment_header:
|
|
215
|
+
response_body = create_402_response(
|
|
216
|
+
amount_usd=self.x402_amount,
|
|
217
|
+
config=config,
|
|
218
|
+
message=self.x402_message,
|
|
219
|
+
)
|
|
220
|
+
response = JsonResponse(response_body, status=402)
|
|
221
|
+
for key, value in create_402_headers().items():
|
|
222
|
+
response[key] = value
|
|
223
|
+
return response
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
result = client.process_payment(
|
|
227
|
+
x_payment_header=payment_header,
|
|
228
|
+
expected_amount_usd=self.x402_amount,
|
|
229
|
+
)
|
|
230
|
+
request.payment_result = result # type: ignore
|
|
231
|
+
return super().dispatch(request, *args, **kwargs) # type: ignore
|
|
232
|
+
|
|
233
|
+
except X402Error as e:
|
|
234
|
+
response = JsonResponse(e.to_dict(), status=402)
|
|
235
|
+
for key, value in create_402_headers().items():
|
|
236
|
+
response[key] = value
|
|
237
|
+
return response
|