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", subdirectory = "rust/x402-axum" }
x402-core = { git = "https://github.com/okx/payments", subdirectory = "rust/x402-core" }
x402-evm  = { git = "https://github.com/okx/payments", subdirectory = "rust/x402-evm" }

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::{DeferredEvmScheme, ExactEvmScheme};

#[tokio::main]
async fn main() {
    // Initialize logging (Facilitator requests/responses visible in terminal)
    tracing_subscriber::fmt::init();

    // Read configuration from environment variables
    let api_key = std::env::var("OKX_API_KEY").expect("xxx");
    let secret_key = std::env::var("OKX_SECRET_KEY").expect("xxx");
    let passphrase = std::env::var("OKX_PASSPHRASE").expect("xxx");
    let pay_to = std::env::var("PAY_TO_ADDRESS")
        .expect("0xb483abdb92f8061e9a3a082a4aaaa6b88c381308");
    let facilitator_url = std::env::var("FACILITATOR_URL")
        .unwrap_or_else(|_| "https://web3.okx.com".to_string());

    // 1. Configure OKX Facilitator
    let facilitator = OkxHttpFacilitatorClient::new(
        &facilitator_url,
        &api_key,
        &secret_key,
        &passphrase,
    );

    // 2. Create Server and register payment schemes
    let server = X402ResourceServer::new(facilitator)
        .register("eip155:196", ExactEvmScheme::new())
        .register("eip155:196", AggrDeferredEvmScheme::new());

    // 3. 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(),           // $0.001 per request
                    network: "eip155:196".into(),      // X Layer
                    pay_to: pay_to.clone(),
                },
            ],
            description: "Get a random joke".into(),
            mime_type: "application/json".into(),
            sync_settle: None,
        }),
    ]);

    // 4. Build Axum router
    let app = Router::new()
        .route("/health", get(health))              // Free
        .route("/api/joke", get(joke))              // Paid $0.001
        .layer(payment_middleware(routes, server));

    // 5. Start the 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.