Quickstart

Build with SDK#

Integrate Onchain OS Payment collection capabilities via SDK. Built-in 402 protocol response and on-chain transaction verification — no need to implement it yourself through the API.

Prerequisites#

Install 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 configuration
[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" }

Integrate Service#

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 (requires OKX API credentials)
const facilitatorClient = new OKXFacilitatorClient({
  apiKey: "OKX_API_KEY",
  secretKey: "OKX_SECRET_KEY",
  passphrase: "OKX_PASSPHRASE",
});

// Create resource server and register EVM exact scheme
const resourceServer = new x402ResourceServer(facilitatorClient);
resourceServer.register(NETWORK, new ExactEvmScheme());

// Mount x402 payment middleware
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,
  ),
);

// Protected image generation route (only executed after payment is verified)
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"                                                                                                                                                                             
      }))
}     

Test Service#

  1. Use Onchain OS to request your service endpoint. You can refer to Buyer Quickstart.
Use onchainOS to access http://localhost:4000/genarateImg
  1. The server returns a 402 status code with PAYMENT-REQUIRED in the response header.
  2. Complete the payment using Agentic Wallet.
  3. Agentic Wallet automatically retries the request.
  4. The server verifies the payment result with the Facilitator and returns the corresponding resource.