Spaces:
Runtime error
Runtime error
| """ | |
| Nory x402 - Payment Infrastructure for AI Agents | |
| Interactive demo showing how AI agents can pay for APIs using the x402 protocol. | |
| """ | |
| import gradio as gr | |
| import requests | |
| import json | |
| # Nory API base URL | |
| NORY_BASE = "https://noryx402.com" | |
| def get_payment_requirements(endpoint: str, amount: str): | |
| """Get x402 payment requirements for an endpoint""" | |
| try: | |
| response = requests.get( | |
| f"{NORY_BASE}/api/x402/requirements", | |
| params={"resource": endpoint, "amount": amount} | |
| ) | |
| if response.status_code == 200: | |
| return json.dumps(response.json(), indent=2) | |
| return f"Error: {response.status_code} - {response.text}" | |
| except Exception as e: | |
| return f"Error: {str(e)}" | |
| def test_paid_api(api_choice: str, param_value: str): | |
| """Test a paid API (returns 402 without payment)""" | |
| endpoints = { | |
| "Crypto Prices": f"/api/paid/live-crypto?symbols={param_value or 'BTC,ETH,SOL'}", | |
| "Weather": f"/api/paid/weather?city={param_value or 'London'}", | |
| "QR Code": f"/api/paid/qr-code?data={param_value or 'https://noryx402.com'}&format=json", | |
| "Web Summary": f"/api/paid/web-summary?url={param_value or 'https://example.com'}", | |
| "Translate": f"/api/paid/translate?text={param_value or 'Hello world'}&to=es", | |
| "Mock Data": f"/api/paid/mock-data?type=users&count={param_value or '3'}" | |
| } | |
| endpoint = endpoints.get(api_choice, endpoints["Crypto Prices"]) | |
| try: | |
| response = requests.get(f"{NORY_BASE}{endpoint}") | |
| if response.status_code == 402: | |
| # Parse the x402 payment requirements | |
| requirements = response.json() | |
| return f"""## 402 Payment Required | |
| The API returned HTTP 402 - payment is required to access this resource. | |
| ### Payment Requirements: | |
| ```json | |
| {json.dumps(requirements, indent=2)} | |
| ``` | |
| ### How an AI Agent Handles This: | |
| 1. **Parse requirements** - Extract amount, wallet address, and network | |
| 2. **Create payment** - Sign a USDC transfer transaction | |
| 3. **Retry request** - Include `X-PAYMENT` header with signed transaction | |
| 4. **Get data** - Server verifies payment, returns data | |
| ### With nory-x402-payer SDK: | |
| ```javascript | |
| import {{ NoryPayer }} from 'nory-x402-payer'; | |
| const payer = new NoryPayer({{ privateKey: 'your-key' }}); | |
| const data = await payer.fetch('{NORY_BASE}{endpoint}'); | |
| // Payment handled automatically! | |
| ``` | |
| """ | |
| elif response.status_code == 200: | |
| return f"""## Success (200 OK) | |
| ```json | |
| {json.dumps(response.json(), indent=2)} | |
| ``` | |
| """ | |
| else: | |
| return f"Error: {response.status_code}\n{response.text}" | |
| except Exception as e: | |
| return f"Error: {str(e)}" | |
| def get_health(): | |
| """Check Nory service health""" | |
| try: | |
| response = requests.get(f"{NORY_BASE}/api/x402/health") | |
| return json.dumps(response.json(), indent=2) | |
| except Exception as e: | |
| return f"Error: {str(e)}" | |
| def get_api_directory(): | |
| """Get list of all paid APIs""" | |
| try: | |
| response = requests.get(f"{NORY_BASE}/api/paid") | |
| if response.status_code == 200: | |
| return json.dumps(response.json(), indent=2) | |
| return f"Error: {response.status_code}" | |
| except Exception as e: | |
| return f"Error: {str(e)}" | |
| # Create Gradio interface | |
| with gr.Blocks( | |
| title="Nory x402 - AI Agent Payments", | |
| theme=gr.themes.Soft(primary_hue="emerald"), | |
| css=""" | |
| .gradio-container { max-width: 1200px !important; } | |
| .gr-button { min-height: 45px; } | |
| """ | |
| ) as demo: | |
| gr.Markdown(""" | |
| # Nory x402 - Payment Infrastructure for AI Agents | |
| **Let AI agents pay for APIs autonomously using the x402 protocol (HTTP 402).** | |
| - Sub-400ms settlement on Solana | |
| - USDC stablecoin payments | |
| - Works with any AI framework (CrewAI, AutoGPT, LangChain, etc.) | |
| [Website](https://noryx402.com) | [Docs](https://noryx402.com/docs) | [npm](https://www.npmjs.com/package/nory-x402-payer) | |
| """) | |
| with gr.Tabs(): | |
| with gr.TabItem("Test Paid APIs"): | |
| gr.Markdown(""" | |
| ### Try a Paid API | |
| Select an API and see the x402 payment flow in action. Without payment, you'll get a 402 response with payment requirements. | |
| """) | |
| with gr.Row(): | |
| api_dropdown = gr.Dropdown( | |
| choices=["Crypto Prices", "Weather", "QR Code", "Web Summary", "Translate", "Mock Data"], | |
| value="Crypto Prices", | |
| label="Select API" | |
| ) | |
| param_input = gr.Textbox( | |
| label="Parameter (optional)", | |
| placeholder="BTC,ETH,SOL | London | URL | etc." | |
| ) | |
| test_btn = gr.Button("Test API (Get 402 Response)", variant="primary") | |
| api_output = gr.Markdown(label="Response") | |
| test_btn.click( | |
| fn=test_paid_api, | |
| inputs=[api_dropdown, param_input], | |
| outputs=api_output | |
| ) | |
| with gr.TabItem("Payment Requirements"): | |
| gr.Markdown(""" | |
| ### Get Payment Requirements | |
| See exactly what payment is needed for any x402-protected resource. | |
| """) | |
| with gr.Row(): | |
| endpoint_input = gr.Textbox( | |
| value="/api/paid/live-crypto", | |
| label="Endpoint" | |
| ) | |
| amount_input = gr.Textbox( | |
| value="0.001", | |
| label="Amount (USDC)" | |
| ) | |
| req_btn = gr.Button("Get Requirements", variant="primary") | |
| req_output = gr.Code(language="json", label="Payment Requirements") | |
| req_btn.click( | |
| fn=get_payment_requirements, | |
| inputs=[endpoint_input, amount_input], | |
| outputs=req_output | |
| ) | |
| with gr.TabItem("API Directory"): | |
| gr.Markdown(""" | |
| ### Available Paid APIs | |
| All x402-enabled endpoints you can pay for and access. | |
| """) | |
| dir_btn = gr.Button("Load API Directory", variant="primary") | |
| dir_output = gr.Code(language="json", label="Paid APIs") | |
| dir_btn.click(fn=get_api_directory, outputs=dir_output) | |
| with gr.TabItem("Health Check"): | |
| gr.Markdown(""" | |
| ### Service Health | |
| Check Nory's service status and supported networks. | |
| """) | |
| health_btn = gr.Button("Check Health", variant="primary") | |
| health_output = gr.Code(language="json", label="Health Status") | |
| health_btn.click(fn=get_health, outputs=health_output) | |
| with gr.TabItem("Integration Code"): | |
| gr.Markdown(""" | |
| ### Integration Examples | |
| #### For AI Agents (Payer SDK) | |
| ```javascript | |
| import { NoryPayer } from 'nory-x402-payer'; | |
| const payer = new NoryPayer({ | |
| privateKey: process.env.SOLANA_PRIVATE_KEY, | |
| network: 'solana-mainnet' | |
| }); | |
| // Automatically handles 402 responses with payment | |
| const { data, payment } = await payer.fetch('https://api.example.com/premium'); | |
| console.log('Data:', data); | |
| console.log('Paid:', payment?.amount, 'USDC'); | |
| ``` | |
| #### For API Providers (Middleware) | |
| ```javascript | |
| import { x402Middleware } from 'nory-x402-middleware'; | |
| app.use('/api/premium', x402Middleware({ | |
| amount: '0.01', // $0.01 USDC | |
| wallet: 'your-wallet', | |
| network: 'solana-mainnet' | |
| })); | |
| ``` | |
| #### MCP Server (for Claude) | |
| ```bash | |
| npm install nory-mcp-server | |
| ``` | |
| Add to Claude Desktop config: | |
| ```json | |
| { | |
| "mcpServers": { | |
| "nory": { | |
| "command": "npx", | |
| "args": ["nory-mcp-server"], | |
| "env": { | |
| "NORY_WALLET_KEY": "your-private-key" | |
| } | |
| } | |
| } | |
| } | |
| ``` | |
| """) | |
| gr.Markdown(""" | |
| --- | |
| ### Resources | |
| - **npm packages**: [nory-x402-payer](https://npmjs.com/package/nory-x402-payer) | [nory-x402-middleware](https://npmjs.com/package/nory-x402-middleware) | [nory-mcp-server](https://npmjs.com/package/nory-mcp-server) | |
| - **Documentation**: [noryx402.com/docs](https://noryx402.com/docs) | |
| - **OpenAPI Spec**: [noryx402.com/openapi.yaml](https://noryx402.com/openapi.yaml) | |
| - **x402 Protocol**: [github.com/coinbase/x402](https://github.com/coinbase/x402) | |
| """) | |
| if __name__ == "__main__": | |
| demo.launch() | |