Overview
What is x402
x402 is a new open payment protocol that enables instant, automatic stablecoin payments directly over HTTP.
Instant access, zero friction. x402 leverages the HTTP 402 Payment Required status code to enable direct stablecoin payments over the web. It replaces complex authentication and paywalls with a simple protocol: pay the network, get the resource. Whether for API monetization or digital content, x402 allows clients—from users to automated bots—to transact instantly without ever needing an account.
Why build with x402?
- Zero-Friction Access: Eliminates the need for accounts, registrations, or complex OAuth flows. Access is granted instantly via payment, creating a stateless "pay-and-go" experience.
- Built for AI Agents: Specifically optimized for machine-to-machine commerce, enabling autonomous agents to handle high-frequency microtransactions and pay-per-request API calls.
- Instant Global Settlement: Utilizes internet-native stablecoin protocols to remove financial intermediaries, ensuring low-cost and immediate settlement for sellers.
- Direct Monetization: Empowers developers and content creators to monetize granularly (e.g., per API call or article) while allowing buyers to access resources programmatically without subscriptions.
How it works
x402 enables programmatic payments over HTTP using a simple request-response flow. When a client requests a paid resource, the server responds with payment requirements, the client submits payment, and the server delivers the resource.
Key features
- Gas subsidies: Make gas-free tokens (whitelisted tokens) transfers and payments on Gate Layer.
- Multi-network support: Gate Layer support. Stay tuned for more networks.
- SDKs: Production-ready client and server libraries.
Payment Flow

API Access and Usage
Before using the API, you need to create a project and generate an API key in the developer portal.
Rate Limiting
To ensure service stability, we enforce rate limits on API requests.
- Rate Limits:
- Per Access Key: Each API endpoint is limited to 1 request per second per Access Key.
- Global Limit: Each specific API action is limited to 50 requests per second globally.
- Response: If these limits are exceeded, the API will return the following error code.
| Error code | Constant Name | Description |
|---|---|---|
| 10131 | RATE_LIMIT_GLOBAL_EXCEEDED | Global rate limit exceeded |
| 10132 | RATE_LIMIT_PER_AK_EXCEEDED | Per access key rate limit exceeded |
| 10133 | RATE_LIMIT_PER_ACTION_EXCEEDED | Per action rate limit exceeded |
Supported networks and crypto
Gate Layer is now supported. Support for more networks is under development. Stay tuned.
| Network | x402 API | ChainIndex |
|---|---|---|
| Gate Layer | Supported | 10088 |
Testnet Facilitator
The x402 testnet facilitator is available for testing and development:
| Network | x402 API | ChainIndex |
|---|---|---|
| Gate Layer Testnet | Supported | 10087 |
Start
Developer Platform
To help you quickly access and manage API services, this guide introduces the main features and usage methods of the Developer Management Platform, including registration/login, API key creation, account security settings, and key management.
- Developer Portal: https://web3.gate.com/api-manage
- Detailed tutorial: https://gateweb3.gitbook.io/gate_dex_api/exploredexapi/en/api-access-and-usage/developer-platform
API List
Introduction
The x402 payment protocol is an HTTP-based payment protocol that enables developers running resource servers to accept payments from users using a variety of payment methods. The x402 Facilitator APIs enable you to facilitate payments using the x402 payment protocol by exposing three APIs.
Get basic information
Request address https://openapi.gateweb3.cc/api/v1/x402
Action
{"action": "x402.supported", "params": {}}
Request parameters
No
Response parameters
| Parameter | Type | Description |
|---|---|---|
| kinds | Array | Array of supported payment types |
| >x402Version | Integer | Version of x402, e.g., 1 |
| >scheme | String | Settlement scheme, e.g., exact (one-time payment of a fixed amount) |
| >network | String | Network identifier, e.g., gatelayer |
| extensions | Array[String] | Extension fields |
Request example
curl -X POST https://openapi.gateweb3.cc/api/v1/x402 \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-H "X-Signature: your-signature" \
-H "X-Timestamp: $(date +%s%3N)" \
-H "X-Request-Id: ${REQUEST_ID}" \
-d '{
"action": "x402.supported",
"params": {
}
}'
Response example
{
"code": 0,
"msg": "",
"data": {
"kinds": [
{
"x402Version": 2,
"scheme": "exact",
"network": "gatelayer_testnet"
}
],
"extensions": []
},
"timestamp": 1769592841
}
Submit transaction
Request address https://openapi.gateweb3.cc/api/v1/x402
Action
{"action": "x402.settle", "params": {}}
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| x402Version | Integer | Yes | x402 protocol version, e.g., 2 |
| paymentPayload | Object | Yes | The x402 payment payload carried by the client along with the request for the protected resource |
| >x402Version | Integer | Yes | x402 protocol version, e.g., 2 |
| >accept | Object | Yes | The settlement scheme to be used |
| >>scheme | String | No | Settlement scheme, e.g., exact (one-time payment of a fixed amount). If empty, returns paymentRequirements. |
| >>network | String | No | Network identifier, e.g., gatelayer. If empty, returns paymentRequirements. |
| >payload | Object | Yes | Payment signature and authorization data object |
| >>signature | String | Yes | Cryptographic signature |
| >>authorization | Object | Yes | Authorization information |
| >>>from | String | Yes | Payer address |
| >>>to | String | Yes | Payee address |
| >>>value | String | Yes | Transfer amount |
| >>>validAfter | String | Yes | Effective time (Unix timestamp) |
| >>>validBefore | String | Yes | Expiration time (Unix timestamp) |
| >>>nonce | String | Yes | Random number (Nonce) to prevent replay attacks |
| paymentRequirements | Object | Yes | Payment details required to access the resource (Amount/Network/Asset/Payee, etc.) |
| >scheme | String | Yes | Settlement scheme, e.g., exact (one-time payment of a fixed amount) |
| >network | String | Yes | Network identifier, e.g., gatelayer |
| >asset | String | Yes | Asset identifier / Contract address (Network dependent) |
| >amount | String | Yes | Transfer amount |
| >payTo | String | Yes | Payee / Recipient |
| >maxTimeoutSeconds | Integer | No | Maximum waiting seconds after the authorization becomes valid |
Response parameters
| Parameter | Type | Description |
|---|---|---|
| success | Boolean | Whether the call was successful |
| payer | String | Payer |
| transaction | String | Transaction Hash |
| errorReason | String | Reason for failure |
| network | String | Network |
Request example
curl -X POST https://openapi.gateweb3.cc/api/v1/x402 \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-H "X-Signature: your-signature" \
-H "X-Timestamp: $(date +%s%3N)" \
-H "X-Request-Id: ${REQUEST_ID}" \
-d '{
"action": "x402.settle",
"params": {
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "gatelayer_testnet"
},
"payload": {
"signature": "0x437830ba...",
"authorization": {
"from": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"to": "0xe734bb6268fcd90756e36c30d6a5fce30569eb6f",
"value": "1111",
"validAfter": "0",
"validBefore": "1768978707",
"nonce": "0x50f24a..."
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "gatelayer_testnet",
"asset": "0x9be8Df37C788B244cFc28E46654aD5Ec28a880AF",
"amount": "1111",
"payTo": "0xe734bb6268fcd90756e36c30d6a5fce30569eb6f",
"maxTimeoutSeconds": 3600
}
}
}'
Response example
Success:
{
"code": 0,
"msg": "",
"data": {
"success": true,
"payer": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"transaction": "0xc36d65c0de132e47852830e27325552a669e2ab6604facc5bddd674ee3eb594c",
"network": "gatelayer_testnet"
},
"timestamp": 1769593302
}
Fail:
{
"code": 200,
"msg": "",
"data": {
"success": false,
"errorReason": "transaction reverted on-chain...",
"transaction": "",
"network": ""
},
"timestamp": 1768997786
}
Verify the transaction
Request address https://openapi.gateweb3.cc/api/v1/x402
Action
{"action": "x402.verify", "params": {}}
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| x402Version | Integer | Yes | x402 protocol version, e.g., 2 |
| paymentPayload | Object | Yes | The x402 payment payload carried by the client along with the protected request |
| >x402Version | Integer | Yes | x402 protocol version, e.g., 2 |
| >accept | Object | No | The settlement scheme to be used |
| >>scheme | String | No | Settlement scheme, e.g., exact (fixed amount one-time payment). |
| >>network | String | No | Network identifier, e.g., gatelayer. |
| >payload | Object | Yes | Payment signature and authorization data object |
| >>signature | String | Yes | Cryptographic signature |
| >>authorization | Object | Yes | Authorization information |
| >>>from | String | Yes | Payer address |
| >>>to | String | Yes | Payee address |
| >>>value | String | Yes | Transfer amount |
| >>>validAfter | String | Yes | Effective time (Unix timestamp) |
| >>>validBefore | String | Yes | Expiration time (Unix timestamp) |
| >>>nonce | String | Yes | Random number (Nonce) to prevent replay attacks |
| paymentRequirements | Object | Yes | Payment details required to access the resource (Amount/Network/Asset/Payee, etc.) |
| >scheme | String | Yes | Settlement scheme, e.g., exact (fixed amount one-time payment) |
| >network | String | Yes | Network identifier, e.g., gatelayer |
| >asset | String | Yes | Asset identifier / Contract address (Network dependent) |
| >amount | String | Yes | Transfer amount |
| >payTo | String | Yes | Payee / Recipient |
| >maxTimeoutSeconds | Integer | No | Maximum waiting seconds after the authorization becomes valid |
Response parameters
| Parameter | Type | Description |
|---|---|---|
| isValid | boolean | Whether it is valid |
| invalidReason | string | Reason for invalidity |
| payer | string | In valid cases, the payer address |
Request example
curl -X POST https://openapi.gateweb3.cc/api/v1/x402 \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-H "X-Signature: your-signature" \
-H "X-Timestamp: $(date +%s%3N)" \
-H "X-Request-Id: ${REQUEST_ID}" \
-d '{
"action": "x402.verify",
"params": { ... }
}'
Response example
Success:
{
"code": 0,
"msg": "",
"data": {
"isValid": true,
"payer": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4"
},
"timestamp": 1769593299
}
Error Codes
| Error Code | Constant Name | Description |
|---|---|---|
| 0 | CodeSuccess | Success |
| 51001 | CodeInvalidPayload | Payment payload invalid or missing |
| 51002 | CodeInvalidRequirements | Payment requirements invalid or missing |
| 51003 | CodeMissingPayloadField | Missing payload field |
| 51101 | CodeUnsupportedNetwork | Unsupported network |
| 51201 | CodeTokenNotFound | Token not found |
| 51301 | CodeInvalidExactPayload | Invalid exact payload format |
| 51302 | CodeMissingSignature | Missing signature |
| 51401 | CodeRecipientMismatch | Recipient address mismatch |
| 51402 | CodeInvalidAuthValue | Invalid auth value format |
| 51403 | CodeInvalidRequiredAmount | Invalid required amount format |
| 51404 | CodeInsufficientAmount | Insufficient amount |
| 51502 | CodeNonceAlreadyUsed | Nonce already used |
| 51602 | CodeInsufficientBalance | Insufficient balance |
| 51701 | CodeInvalidSignatureFormat | Invalid signature format |
| 51702 | CodeInvalidSignatureLength | Invalid signature length (should be 65 bytes) |
| 51704 | CodeInvalidSignature | Invalid signature |
| 51901 | CodeInvalidValueFormat | Invalid value format |
| 51902 | CodeInvalidValidAfterFormat | Invalid validAfter format |
| 51903 | CodeInvalidValidBeforeFormat | Invalid validBefore format |
| 51904 | CodeInvalidNonceFormat | Invalid nonce format |
| 51905 | CodeInvalidNonceLength | Invalid nonce length (should be 32 bytes) |
Guidelines
Payment case
This guide will show you how to create a Go client that can initiate paid requests to x402-protected resources.
Prerequisites
Before starting, ensure you have:
- A crypto wallet with USDC (any EVM-compatible wallet)
- Go 1.24+ installed
- A service requiring payment via x402
1. Install Dependencies
Add the x402 Go module to your project:
go get [github.com/gatechain/x402/go](https://github.com/gatechain/x402/go)
2. Create a Payment-enabled HTTP Client
The SDK automatically handles payment creation and signing using the chain's DOMAIN_SEPARATOR. For gatelayer_testnet, it uses the correct DOMAIN_SEPARATOR from the token contract to ensure valid signatures.
Here is a complete runnable example:
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"time"
x402 "[github.com/gatechain/x402/go](https://github.com/gatechain/x402/go)"
x402http "[github.com/gatechain/x402/go/http](https://github.com/gatechain/x402/go/http)"
evm "[github.com/gatechain/x402/go/mechanisms/evm/exact/client](https://github.com/gatechain/x402/go/mechanisms/evm/exact/client)"
evmsigners "[github.com/gatechain/x402/go/signers/evm](https://github.com/gatechain/x402/go/signers/evm)"
)
func main() {
// Get configuration from environment
privateKey := os.Getenv("EVM_PRIVATE_KEY")
if privateKey == "" {
fmt.Println("❌ EVM_PRIVATE_KEY environment variable is required")
os.Exit(1)
}
url := os.Getenv("SERVER_URL")
if url == "" {
url = "http://localhost:4021/weather"
}
fmt.Printf("🚀 Making paid request to: %s\n\n", url)
// Create EVM signer from private key
evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(privateKey)
if err != nil {
fmt.Printf("❌ Failed to create signer: %v\n", err)
os.Exit(1)
}
fmt.Printf("✅ Signer created: %s\n\n", evmSigner.Address())
// Create x402 client and register EVM scheme
// The SDK automatically uses the chain's DOMAIN_SEPARATOR for signing
// For gatelayer_testnet, it uses the correct DOMAIN_SEPARATOR from the chain
x402Client := x402.Newx402Client().
Register("gatelayer_testnet", evm.NewExactEvmScheme(evmSigner))
// Wrap HTTP client with payment handling
// PaymentRoundTripper automatically handles 402 responses and retries with payment
httpClient := x402http.WrapHTTPClientWithPayment(
http.DefaultClient,
x402http.Newx402HTTPClient(x402Client),
)
// Make request - payment is handled automatically
// The PaymentRoundTripper will:
// 1. Make the initial request
// 2. If it receives a 402 Payment Required response, it will:
// - Parse the payment requirements from the response
// - Create a payment payload using the chain's DOMAIN_SEPARATOR
// - Sign the payment payload
// - Retry the request with the payment header
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
fmt.Printf("❌ Failed to create request: %v\n", err)
os.Exit(1)
}
resp, err := httpClient.Do(req)
if err != nil {
fmt.Printf("❌ Request failed: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
// Check response status
if resp.StatusCode != http.StatusOK {
body, _ := json.Marshal(map[string]interface{}{
"status": resp.StatusCode,
"message": "Request failed",
})
fmt.Printf("❌ HTTP %d: %s\n", resp.StatusCode, string(body))
os.Exit(1)
}
// Read response
var data map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
fmt.Printf("❌ Failed to decode response: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ Response received:")
prettyJSON, _ := json.MarshalIndent(data, " ", " ")
fmt.Printf("%s\n\n", string(prettyJSON))
// Check payment response header
paymentHeader := resp.Header.Get("PAYMENT-RESPONSE")
if paymentHeader == "" {
paymentHeader = resp.Header.Get("X-PAYMENT-RESPONSE")
}
if paymentHeader != "" {
fmt.Println("💰 Payment settled successfully!")
fmt.Printf(" Payment header: %s\n", paymentHeader)
}
}
3. How It Works
The wrapped HTTP client automatically:
- Detects 402 Responses: When the server responds with
402 Payment Required, the client extracts payment requirements from thePAYMENT-REQUIREDheader. - Creates Payment Payload: The client creates a signed payment payload using the registered payment scheme.
- Retries with Payment: The client automatically retries the request with the
X-PAYMENTheader containing the payment payload. - Handles Settlement: After successful payment verification, the server returns the resource and includes settlement confirmation in the
PAYMENT-RESPONSEheader.
Configuration
Environment Variables
For Gate Web3 OpenAPI authentication, set the following environment variables:
# Required
export GATE_WEB3_API_KEY="your-api-key"
export GATE_WEB3_API_SECRET="your-api-secret"
# Optional
export GATE_WEB3_PASSPHRASE="your-passphrase"
export GATE_WEB3_REAL_IP="your-real-ip" # Defaults to 127.0.0.1
Facilitator Configuration
The facilitator client defaults to using Gate Web3 OpenAPI:
facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
URL: "[https://openapi-test.gateweb3.cc/api/v1/x402](https://openapi-test.gateweb3.cc/api/v1/x402)",
// Optional: Custom HTTP client
HTTPClient: &http.Client{
Timeout: 30 * time.Second,
},
// Optional: Custom auth provider
AuthProvider: &MyAuthProvider{},
})
Collection case
This guide will show you how to integrate x402 into your Go server to accept payments for APIs or services.
Prerequisites
Before starting, ensure you have:
- A crypto wallet for receiving funds (any EVM-compatible wallet)
- Go 1.24+ installed
- An existing HTTP server (Gin, standard library, etc.)
1. Install Dependencies
Add the x402 Go module to your project:
go get [github.com/gatechain/x402/go](https://github.com/gatechain/x402/go)
2. Set Environment Variables
Set the required environment variables before running the server:
# Required: Wallet address to receive payments
export PAYEE_ADDRESS="0x1234567890123456789012345678901234567890"
# Required for Gate Web3 OpenAPI authentication
export GATE_WEB3_API_KEY="your-api-key"
export GATE_WEB3_API_SECRET="your-api-secret"
# Optional
export GATE_WEB3_PASSPHRASE="your-passphrase"
export GATE_WEB3_REAL_IP="your-real-ip"
3. Create a Payment-Protected Server
Here is a complete runnable example using the Gin framework:
package main
import (
"fmt"
"net/http"
"os"
"time"
"[github.com/gin-gonic/gin](https://github.com/gin-gonic/gin)"
x402 "[github.com/gatechain/x402/go](https://github.com/gatechain/x402/go)"
x402http "[github.com/gatechain/x402/go/http](https://github.com/gatechain/x402/go/http)"
ginmw "[github.com/gatechain/x402/go/http/gin](https://github.com/gatechain/x402/go/http/gin)"
evm "[github.com/gatechain/x402/go/mechanisms/evm/exact/server](https://github.com/gatechain/x402/go/mechanisms/evm/exact/server)"
)
func main() {
// Get receiving wallet address from environment variable
payTo := os.Getenv("PAYEE_ADDRESS")
if payTo == "" {
fmt.Println("❌ PAYEE_ADDRESS environment variable is required")
fmt.Println(" Example: export PAYEE_ADDRESS=0x1234567890123456789012345678901234567890")
os.Exit(1)
}
network := x402.Network("gatelayer_testnet") // Gate Layer testnet
fmt.Printf("🚀 Starting x402 payment server...\n")
fmt.Printf(" Payee address: %s\n", payTo)
fmt.Printf(" Network: %s\n", network)
fmt.Printf(" Facilitator: [https://openapi-test.gateweb3.cc/api/v1/x402](https://openapi-test.gateweb3.cc/api/v1/x402)\n\n")
r := gin.Default()
// Create facilitator client (Gate Web3 OpenAPI Testnet)
// The client will automatically use Gate Web3 authentication if environment variables are set:
// - GATE_WEB3_API_KEY
// - GATE_WEB3_API_SECRET
// - GATE_WEB3_PASSPHRASE (optional)
// - GATE_WEB3_REAL_IP (optional)
facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
URL: "[https://openapi-test.gateweb3.cc/api/v1/x402](https://openapi-test.gateweb3.cc/api/v1/x402)",
})
// Apply x402 payment middleware
r.Use(ginmw.X402Payment(ginmw.Config{
Routes: x402http.RoutesConfig{
"GET /weather": {
Accepts: x402http.PaymentOptions{
{
Scheme: "exact",
PayTo: payTo,
Price: "$0.001", // Price in USD - automatically converts to USDC on the network
Network: network,
},
},
Description: "Get weather data for a city",
MimeType: "application/json",
},
},
Facilitator: facilitatorClient,
Schemes: []ginmw.SchemeConfig{
{Network: network, Server: evm.NewExactEvmScheme()},
},
SyncFacilitatorOnStart: true,
Timeout: 30 * time.Second,
}))
// Protected endpoint
r.GET("/weather", func(c *gin.Context) {
city := c.DefaultQuery("city", "San Francisco")
c.JSON(http.StatusOK, gin.H{
"city": city,
"weather": "sunny",
"temperature": 70,
"timestamp": time.Now().Format(time.RFC3339),
})
})
// Health check endpoint (no payment required)
r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"version": "1.0.0",
})
})
fmt.Printf(" Server listening on http://localhost:4021\n")
if err := r.Run(":4021"); err != nil {
fmt.Printf("❌ Error starting server: %v\n", err)
os.Exit(1)
}
}
4. Test Your Integration
Start your server:
go run main.go
Make a request without payment:
curl http://localhost:4021/weather
The server will respond with 402 Payment Required, including payment instructions in the PAYMENT-REQUIRED header. Use a compatible client to complete payment and retry the request. After successful payment verification, the server will return your API response.