|
20 | 20 | PaymentPayload, |
21 | 21 | PaymentRequirements, |
22 | 22 | Price, |
| 23 | + SettleResponse, |
23 | 24 | x402PaymentRequiredResponse, |
24 | 25 | PaywallConfig, |
25 | 26 | SupportedNetworks, |
26 | 27 | HTTPInputSchema, |
27 | 28 | ) |
28 | 29 |
|
| 30 | +import os |
| 31 | +import httpx |
| 32 | + |
| 33 | + |
29 | 34 | logger = logging.getLogger(__name__) |
30 | 35 |
|
31 | 36 |
|
@@ -206,10 +211,54 @@ def x402_response(error: str): |
206 | 211 |
|
207 | 212 | # Settle the payment |
208 | 213 | try: |
209 | | - |
210 | | - settle_response = await facilitator.settle( |
211 | | - payment, selected_payment_requirements |
212 | | - ) |
| 214 | + custom_facilitator_url = os.getenv("CUSTOM_FACILITATOR_API_URL", "") |
| 215 | + custom_facilitator_succeeded = False |
| 216 | + custom_facilitator_response = None |
| 217 | + |
| 218 | + if custom_facilitator_url: |
| 219 | + try: |
| 220 | + url = f"{custom_facilitator_url.rstrip('/')}/api/x402/facilitators/settle" |
| 221 | + headers = {"x-payment": payment_header} |
| 222 | + async with httpx.AsyncClient(timeout=60.0) as client: |
| 223 | + custom_facilitator_response = await client.post(url, headers=headers) |
| 224 | + custom_facilitator_response.raise_for_status() |
| 225 | + custom_facilitator_succeeded = True |
| 226 | + logger.info(f"Custom facilitator settle succeeded") |
| 227 | + except Exception as e: |
| 228 | + logger.warning(f"Custom facilitator settle POST failed: {e}, falling back to default facilitator") |
| 229 | + custom_facilitator_succeeded = False |
| 230 | + |
| 231 | + # Fallback to default facilitator if custom facilitator wasn't used or failed |
| 232 | + if not custom_facilitator_succeeded: |
| 233 | + settle_response = await facilitator.settle( |
| 234 | + payment, selected_payment_requirements |
| 235 | + ) |
| 236 | + else: |
| 237 | + # If custom facilitator succeeded, we still need a settle_response for the response headers |
| 238 | + # Create a minimal success response |
| 239 | + try: |
| 240 | + payer = payment.payload.authorization.from_ |
| 241 | + except (AttributeError, KeyError): |
| 242 | + payer = "" |
| 243 | + |
| 244 | + # Extract transaction hash from custom facilitator response |
| 245 | + transaction_hash = "" |
| 246 | + try: |
| 247 | + if custom_facilitator_response: |
| 248 | + response_data = custom_facilitator_response.json() |
| 249 | + if isinstance(response_data, dict) and "data" in response_data: |
| 250 | + data = response_data["data"] |
| 251 | + if isinstance(data, dict) and "transactionHash" in data: |
| 252 | + transaction_hash = data["transactionHash"] |
| 253 | + except (AttributeError, KeyError, ValueError, httpx.DecodeError) as e: |
| 254 | + logger.warning(f"Failed to extract transactionHash from custom facilitator response: {e}") |
| 255 | + |
| 256 | + settle_response = SettleResponse( |
| 257 | + success=True, |
| 258 | + transaction=transaction_hash, |
| 259 | + network=selected_payment_requirements.network, |
| 260 | + payer=payer, |
| 261 | + ) |
213 | 262 |
|
214 | 263 | if settle_response.success: |
215 | 264 | response.headers["X-PAYMENT-RESPONSE"] = base64.b64encode( |
|
0 commit comments