快速开始

通过 SDK 接入#

通过 SDK 接入 Onchain OS Payment 收款能力。内置 402 协议响应与链上交易验证,无需自行通过 API 实现。

准备工作#

安装 SDK#

Node.js

Shell
npm install express @okxweb3/x402-express @okxweb3/x402-core @okxweb3/x402-evm
npm install -D typescript tsx @types/express @types/node

Go

Shell
go get github.com/okx/payments/go

Rust

Toml
# Cargo.toml 中配置
[dependencies]
x402-axum = { git = "https://github.com/okx/payments" }
x402-core = { git = "https://github.com/okx/payments" }
x402-evm  = { git = "https://github.com/okx/payments" }

接入服务#

Node.js

Typescript
import express from "express";
import {
  paymentMiddleware,
  x402ResourceServer,
} from "@okxweb3/x402-express";
import { ExactEvmScheme } from "@okxweb3/x402-evm/exact/server";
import { OKXFacilitatorClient } from "@okxweb3/x402-core";

const app = express();

const NETWORK = "eip155:196"; // X Layer Mainnet
const PAY_TO = process.env.PAY_TO_ADDRESS || "0xYourWalletAddress";

// OKX Facilitator Client(需要 OKX API 凭证)
const facilitatorClient = new OKXFacilitatorClient({
  apiKey: "OKX_API_KEY",
  secretKey: "OKX_SECRET_KEY",
  passphrase: "OKX_PASSPHRASE",
});

// 创建资源服务器并注册 EVM exact scheme
const resourceServer = new x402ResourceServer(facilitatorClient);
resourceServer.register(NETWORK, new ExactEvmScheme());

// 挂载 x402 支付中间件
app.use(
  paymentMiddleware(
    {
      "GET /generateImg": {
        accepts: [{
          scheme: "exact",
          network: NETWORK,
          payTo: PAY_TO,
          price: "$0.01", // USDT 0.01
        }],
        description: "AI Image Generation Service",
        mimeType: "application/json",
      },
    },
    resourceServer,
  ),
);

// 受保护的图片生成路由(支付通过后才会执行)
app.get("/generateImg", (_req, res) => {
  console.log("[Seller] Payment verified, generating image...");
  res.json({
    success: true,
    imageUrl: "https://placehold.co/512x512/png?text=AI+Generated",
    prompt: "a sunset over mountains",
    timestamp: new Date().toISOString(),
  });
});

app.listen(4000, () => {
  console.log("[Seller] Image generation service listening at http://localhost:4000");
  console.log("[Seller] Protected route: GET http://localhost:4000/generateImg");
  console.log(`[Seller] Network: ${NETWORK}, PayTo: ${PAY_TO}`);
});

Go

Go
package main

import (
    "net/http"
    "os"
    "time"

    ginfw "github.com/gin-gonic/gin"
    x402http "github.com/okx/payments/go/http"
    ginmw "github.com/okx/payments/go/http/gin"
    evm "github.com/okx/payments/go/mechanisms/evm/exact/server"
)

func main() {
    // 1. Create OKX Facilitator client
    facilitator, _ := x402http.NewOKXFacilitatorClient(&x402http.OKXFacilitatorConfig{
        Auth: x402http.OKXAuthConfig{
            APIKey:     os.Getenv("OKX_API_KEY"),
            SecretKey:  os.Getenv("OKX_SECRET_KEY"),
            Passphrase: os.Getenv("OKX_PASSPHRASE"),
        },
    })

    // 2. Define payment-protected routes
    routes := x402http.RoutesConfig{
        "GET /generateImg": {
            Accepts: x402http.PaymentOptions{
                {
                    Scheme:  "exact",
                    Price:   "$0.01",
                    Network: "eip155:196",
                    PayTo:   "0xYourWalletAddress",
                },
            },
            Description: "AI-generated image",
            MimeType:    "image/png",
        },
    }

    // 3. Create Gin router with payment middleware
    r := ginfw.Default()
    r.Use(ginmw.X402Payment(ginmw.Config{
        Routes:      routes,
        Facilitator: facilitator,
        Schemes: []ginmw.SchemeConfig{
            {Network: "eip155:196", Server: evm.NewExactEvmScheme()},
        },
        Timeout: 30 * time.Second,
    }))

    r.GET("/genarateImg", func(c *ginfw.Context) {
        c.JSON(http.StatusOK, ginfw.H{"image": "https://placehold.co/512x512/png?text=AI+Generated"})
    })

    r.Run(":4000")
}

Rust

Rust
use std::collections::HashMap;                                                                                                                                                                        
                                                                                                                                                                                                        
use axum::{routing::get, Json, Router};
use serde_json::{json, Value};                                                                                                                                                                        
                                                                                                                                                                                                    
use x402_axum::{payment_middleware, AcceptConfig, RoutePaymentConfig};                                                                                                                                
use x402_core::http::OkxHttpFacilitatorClient;
use x402_core::server::X402ResourceServer;                                                                                                                                                            
use x402_evm::{AggrDeferredEvmScheme, ExactEvmScheme};
                                                                                                                                                                                                    
#[tokio::main]  
async fn main() {
      // Initialize tracing (see Facilitator request/response logs in terminal)
      tracing_subscriber::fmt::init();                                                                                                                                                                  
    
      // Read configuration from environment variables                                                                                                                                                  
      let api_key = std::env::var("OKX_API_KEY").expect("OKX_API_KEY is required");
      let secret_key = std::env::var("OKX_SECRET_KEY").expect("OKX_SECRET_KEY is required");                                                                                                            
      let passphrase = std::env::var("OKX_PASSPHRASE").expect("OKX_PASSPHRASE is required");                                                                                                            
      let pay_to = std::env::var("PAY_TO_ADDRESS")
          .unwrap_or_else(|_| "0xb483abdb92...aa6b88c381308".to_string());                                                                                                                
                  
      // 1. Configure OKX Facilitator                                                                                                                                                                   
      let facilitator = match std::env::var("FACILITATOR_URL") {
          Ok(url) => OkxHttpFacilitatorClient::with_url(&url, &api_key, &secret_key, &passphrase),                                                                                                      
          Err(_) => OkxHttpFacilitatorClient::new(&api_key, &secret_key, &passphrase),
      }                                                                                                                                                                                                 
      .expect("Failed to create facilitator client");
                                                                                                                                                                                                        
      // 2. Create Server and register payment schemes
      let mut server = X402ResourceServer::new(facilitator)
          .register("eip155:196", ExactEvmScheme::new())                                                                                                                                                
          .register("eip155:196", AggrDeferredEvmScheme::new());
                                                                                                                                                                                                        
      // 3. Must initialize (fetches supported schemes from facilitator)                                                                                                                                
      server
          .initialize()                                                                                                                                                                                 
          .await  
          .expect("Failed to initialize: check facilitator connectivity");
    
      // 4. Configure which routes require payment
      let routes = HashMap::from([(
          "GET /api/joke".to_string(),
          RoutePaymentConfig {                                                                                                                                                                          
              accepts: vec![AcceptConfig {
                  scheme: "exact".into(),                                                                                                                                                               
                  price: "$0.001".into(),
                  network: "eip155:196".into(),
                  pay_to: pay_to.clone(),
                  max_timeout_seconds: None,                                                                                                                                                            
                  extra: None,
              }],                                                                                                                                                                                       
              description: "Get a random joke".into(),
              mime_type: "application/json".into(),
              sync_settle: None,
          },
      )]);                                                                                                                                                                                              
    
      // 5. Build Axum router                                                                                                                                                                           
      let app = Router::new()
          .route("/health", get(health))
          .route("/api/joke", get(joke))
          .layer(payment_middleware(routes, server));
    
      // 6. Start server                                                                                                                                                                                
      let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
          .await                                                                                                                                                                                        
          .unwrap();
      println!("========================================");
      println!("  Your paid API is running!");
      println!("  Free endpoint:  http://localhost:3000/health");                                                                                                                                       
      println!("  Paid endpoint:  http://localhost:3000/api/joke ($0.001)");
      println!("========================================");                                                                                                                                             
      axum::serve(listener, app).await.unwrap();                                                                                                                                                        
    }
                                                                                                                                                                                                     
    // Free endpoint
    async fn health() -> Json<Value> {
      Json(json!({ "status": "ok" }))
    }
    
    // Paid endpoint - requires $0.001 payment to access                                                                                                                                                  
    async fn joke() -> Json<Value> {
      Json(json!({                                                                                                                                                                                      
          "joke": "Why do programmers always confuse Halloween and Christmas? Because Oct 31 = Dec 25",
          "price": "$0.001"                                                                                                                                                                             
      }))
}     

测试服务#

  1. 使用 Onchain OS 请求您的服务端口,可以参考 我是买家
请使用onchainOS访问http://localhost:4000/genarateImg
  1. 服务器返回 402 状态码,并在响应头中包含 PAYMENT-REQUIRED
  2. 使用 Agentic Wallet 完成支付。
  3. Agentic Wallet 自动重试请求。
  4. 服务端会向 Facilitator 验证支付结果,并返回对应资源。