Skip to main content

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.
  • Multiple Token Payment Options: Pay with any ERC-20 token via Permit2; EIP-3009 tokens like USDC offer the best frictionless experience.
  • SDKs: TypeScript & Go SDK — production-ready client and server libraries.

Payment Flow

  • EIP-3009 Token EIP-3009 token payment flow
  • Generic ERC-20 tokens (Permit2) ERC-20 Permit2 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 codeConstant NameDescription
10131RATE_LIMIT_GLOBAL_EXCEEDEDGlobal rate limit exceeded
10132RATE_LIMIT_PER_AK_EXCEEDEDPer access key rate limit exceeded
10133RATE_LIMIT_PER_ACTION_EXCEEDEDPer action rate limit exceeded

Supported networks and crypto

Supported networks:

NetworkschemaIdentifierx402 APIChainIndex
Gate LayerexactgatelayerSupported10088
EthereumexactethSupported1
BaseexactbaseSupported8453
PolygonexactPolygonSupported137
Arbitrum OneexactArbitrum OneSupported42161
BSCexactbscSupported56
SolanaexactsolanaSupported101

Supported token:

  • EIP-3009 Tokens
NetworkTokenContract address
GatelayerGUSD0xECE3F96198a5E6B9b2278edbEa8d548F66050d1c
Gatelayerusdc.e0x8a2B28364102Bea189D99A475C494330Ef2bDD0B
EthereumUSDC0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
BaseUSDC0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Arbitrum OneUSDC0xaf88d065e77c8cc2239327c5edb3a432268e5831
PolygonUSDC0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359
  • Generic ERC-20 tokens (Permit2)
NetworkTokenContract address
EthereumUSDT0xdac17f958d2ee523a2206206994597c13d831ec7
BSCUSDC0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d
BSCUSDT0x55d398326f99059ff775485246999027b3197955
BSCUSD10x8d0d000ee44948fc98c9b98a4fa4921476f08b0d
BaseUSDT0xfde4c96c8593536e31f229ea8f37b2ada2699bb2
  • Non-EVM Chain Tokens
NetworkTokenContract address
SolanaUSDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
SolanaUSDTEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB

Testnet Facilitator

The x402 testnet facilitator is available for testing and development:

NetworkschemaIdentifierx402 APIChainIndex
Gate Layer Testnetexactgatelayer_testnetSupported10087
Solana Devnetexactsolana-devnetSupported103

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.


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": "x402.supported", "params": {} }

Request parameters

No

Response parameters

ParameterTypeDescription
kindsArrayArray of supported payment types
>x402VersionIntegerVersion of x402, e.g., 1
>schemeStringSettlement scheme, e.g., exact (one-time payment of a fixed amount)
>networkStringNetwork identifier, e.g., gatelayer
extensionsArray[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": {
}
}'

Request example (Permit2)

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": {
"extensions": ["permit2"]
}
}'

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": "x402.settle", "params": {} }

Request parameters

ParameterTypeRequiredDescription
x402VersionIntegerYesx402 protocol version, e.g., 2
paymentPayloadObjectYesThe x402 payment payload carried by the client along with the request for the protected resource
>x402VersionIntegerYesx402 protocol version, e.g., 2
>acceptedObjectYesThe settlement scheme to be used
>>schemeStringNoSettlement scheme, e.g., exact (one-time payment of a fixed amount). If empty, returns paymentRequirements.
>>networkStringNoNetwork identifier, e.g., gatelayer. If empty, returns paymentRequirements.
>payloadObjectYesPayment signature and authorization data object
>>signatureStringYesCryptographic signature
>>authorizationObjectNoEIP-3009 authorization info (fill when using EIP-3009)
>>>fromStringYesPayer address
>>>toStringYesPayee address
>>>valueStringYesTransfer amount
>>>validAfterStringYesEffective time (Unix timestamp)
>>>validBeforeStringYesExpiration time (Unix timestamp)
>>>nonceStringYesRandom number (Nonce) to prevent replay attacks
>>permit2AuthorizationObjectNoPermit2 authorization info (fill when assetTransferMethod=permit2)
>>>fromStringYesPayer address
>>>spenderStringYesPermit2 proxy spender (eth/base: 0x3765Cf99CEE0075aFd6Cafe103b1c78Ed75aC9Bf, bsc: 0x701cCFfcdE34b92B16599Ac865AA1395A1a1F38c)
>>>permittedObjectYesPermit2 token/amount
>>>>tokenStringYesToken contract address
>>>>amountStringYesPermitted amount
>>>nonceStringYesPermit2 nonce
>>>deadlineStringYesPermit2 deadline (Unix)
>>>witnessObjectYesWitness information
>>>>toStringYeswitness.to (recipient address)
>>>>validAfterStringYeswitness.validAfter (Unix)
paymentRequirementsObjectYesPayment details required to access the resource (Amount/Network/Asset/Payee, etc.)
>schemeStringYesSettlement scheme, e.g., exact (one-time payment of a fixed amount)
>networkStringYesNetwork identifier, e.g., gatelayer
>assetStringYesAsset identifier / Contract address (Network dependent)
>amountStringYesTransfer amount (token's smallest unit / atomic unit). E.g. for 6-decimal tokens, 10000 = 0.01
>payToStringYesPayee / Recipient
>maxTimeoutSecondsIntegerNoMaximum waiting seconds after the authorization becomes valid
>extra.assetTransferMethodStringNoAsset transfer method: permit2 means use Permit2 (must be paired with payload.permit2Authorization)

Response parameters

ParameterTypeDescription
successBooleanWhether the call was successful
payerStringPayer
transactionStringTransaction Hash
errorReasonStringReason for failure
networkStringNetwork

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": "0x437830ba823c6d680c43fa820af1acdef16da9db3c58e031031c3a8051e5f1c6379d6cae031a1c5601e81aa866768ec35d6b794351dc7c1b598a74ff2fda93c21b",
"authorization": {
"from": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"to": "0xe734bb6268fcd90756e36c30d6a5fce30569eb6f",
"value": "1111",
"validAfter": "0",
"validBefore": "1768978707",
"nonce": "0x50f24a1d09b9aa10dd5b8365d871f729303362f7f48269ab431d2f4f90895355"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "gatelayer_testnet",
"asset": "0x9be8Df37C788B244cFc28E46654aD5Ec28a880AF",
"amount": "1111",
"payTo": "0xe734bb6268fcd90756e36c30d6a5fce30569eb6f",
"maxTimeoutSeconds": 3600
}
}
}'

Request example (Permit2)

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": "eth"
},
"payload": {
"permit2Authorization": {
"deadline": "1774345660",
"from": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"nonce": "1",
"permitted": {
"amount": "100",
"token": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
},
"spender": "0x3765Cf99CEE0075aFd6Cafe103b1c78Ed75aC9Bf",
"witness": {
"to": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"validAfter": "0"
}
},
"signature": "0xedffa6e319f7ff02b438bb9ce9439ea4fb7a91f965aa3289ea5405c7deb2d80126c32970e8ec45c422ef498cd6c71edf65a00f18cbe919c4ce587e33f5f6ff031c"
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eth",
"asset": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"amount": "100",
"payTo": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"extra": {
"assetTransferMethod": "permit2"
}
}
}
}'

Amount unit note: The amount/value in all examples are in the token's smallest unit (not human-readable decimals). For a 6-decimal token: 1111 = 0.001111, 100 = 0.0001.

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 0x38a864a30dadea91b66ce3bff870a0ead1be4fcc8a647fc58c2f12d1516afca5 reverted on-chain at block 11943682",
"transaction": "",
"network": ""
},
"timestamp": 1768997786
}

Verify the transaction

Request address https://openapi.gateweb3.cc/api/v1/x402

{ "action": "x402.verify", "params": {} }

Request parameters

ParameterTypeRequiredDescription
x402VersionIntegerYesx402 protocol version, e.g., 2
paymentPayloadObjectYesThe x402 payment payload carried by the client along with the protected request
>x402VersionIntegerYesx402 protocol version, e.g., 2
>acceptedObjectNoThe settlement scheme to be used
>>schemeStringNoSettlement scheme, e.g., exact (fixed amount one-time payment)
>>networkStringNoNetwork identifier, e.g., gatelayer
>payloadObjectYesPayment signature and authorization data object
>>signatureStringYesCryptographic signature
>>authorizationObjectNoEIP-3009 authorization info (fill when using EIP-3009)
>>>fromStringYesPayer address
>>>toStringYesPayee address
>>>valueStringYesTransfer amount
>>>validAfterStringYesEffective time (Unix timestamp)
>>>validBeforeStringYesExpiration time (Unix timestamp)
>>>nonceStringYesRandom number (Nonce) to prevent replay attacks
>>permit2AuthorizationObjectNoPermit2 authorization info (fill when assetTransferMethod=permit2)
>>>fromStringYesPayer address
>>>spenderStringYesPermit2 proxy spender (eth/base: 0x3765Cf99CEE0075aFd6Cafe103b1c78Ed75aC9Bf, bsc: 0x701cCFfcdE34b92B16599Ac865AA1395A1a1F38c)
>>>permittedObjectYesPermit2 token/amount
>>>>tokenStringYesToken contract address
>>>>amountStringYesPermitted amount
>>>nonceStringYesPermit2 nonce
>>>deadlineStringYesPermit2 deadline (Unix)
>>>witnessObjectYesWitness information
>>>>toStringYeswitness.to (recipient address)
>>>>validAfterStringYeswitness.validAfter (Unix)
paymentRequirementsObjectYesPayment details required to access the resource (Amount/Network/Asset/Payee, etc.)
>schemeStringYesSettlement scheme, e.g., exact (fixed amount one-time payment)
>networkStringYesNetwork identifier, e.g., gatelayer
>assetStringYesAsset identifier / Contract address (Network dependent)
>amountStringYesTransfer amount (token's smallest unit / atomic unit). E.g. for 6-decimal tokens, 10000 = 0.01
>payToStringYesPayee / Recipient
>maxTimeoutSecondsIntegerNoMaximum waiting seconds after the authorization becomes valid
>extra.assetTransferMethodStringNoAsset transfer method: permit2 means use Permit2 (must be paired with payload.permit2Authorization)

Response parameters

ParameterTypeDescription
isValidbooleanWhether it is valid
invalidReasonstringReason for invalidity
payerstringIn 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": {
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "gatelayer_testnet"
},
"payload": {
"signature": "0x437830ba823c6d680c43fa820af1acdef16da9db3c58e031031c3a8051e5f1c6379d6cae031a1c5601e81aa866768ec35d6b794351dc7c1b598a74ff2fda93c21b",
"authorization": {
"from": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"to": "0xe734bb6268fcd90756e36c30d6a5fce30569eb6f",
"value": "1111",
"validAfter": "0",
"validBefore": "1768978707",
"nonce": "0x50f24a1d09b9aa10dd5b8365d871f729303362f7f48269ab431d2f4f90895355"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "gatelayer_testnet",
"asset": "0x9be8Df37C788B244cFc28E46654aD5Ec28a880AF",
"amount": "1111",
"payTo": "0xe734bb6268fcd90756e36c30d6a5fce30569eb6f",
"maxTimeoutSeconds": 3600
}
}
}'

Request example (Permit2)

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": {
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "eth"
},
"payload": {
"permit2Authorization": {
"deadline": "1774345660",
"from": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"nonce": "1",
"permitted": {
"amount": "100",
"token": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
},
"spender": "0x3765Cf99CEE0075aFd6Cafe103b1c78Ed75aC9Bf",
"witness": {
"to": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"validAfter": "0"
}
},
"signature": "0xedffa6e319f7ff02b438bb9ce9439ea4fb7a91f965aa3289ea5405c7deb2d80126c32970e8ec45c422ef498cd6c71edf65a00f18cbe919c4ce587e33f5f6ff031c"
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eth",
"asset": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"amount": "100",
"payTo": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4",
"extra": {
"assetTransferMethod": "permit2"
}
}
}
}'

Request example (Solana)

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": {
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "solana-devnet"
},
"payload": {
"transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7q9i+x44wnyXybrVzEunIEa8xcnsuTbVONuAvCYKQHieUB+9eP86tpYNHHw29o/+kzfqZLjkCposQmxdi868LgAIBBAgbw1xMgvndUnCY2H5iyPEOv0OWixAUZadhCZ/UR+gbHYEIqcQndRHFtNnl1ViE+P5Pgf29VbWHZi2Fy8Reop9oQz+vpyWh8YsyIXfaca60bbSpTKssypuO545X8tpdIPUKZRwNNVTihwOaySpu5eXDE5IqDgjhUO+cn5ia054J9pp2+sEqFk7q5ZZDSEmDXbkEx1mSwO1SgyvULFbIYc0UAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqQVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNqQws4gKC61QaRl7IvU/2yJxT7e/jzicQper6CVLZknIEBQAFAiBOAAAFAAkDAQAAAAAAAAAGBAIEAwEKDOgDAAAAAAAABgcAIDg5ZDRiZDFhZTJiNmVmMDE5ZjhmYmViODNiZmZlNWRhAA=="
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "solana-devnet",
"asset": "BPy1fp1Hb1v6Rr41ayPs8ttRUrjjNqkApudTiinNucg3",
"amount": "1000",
"payTo": "9iuLQj4Xr7HAduaym6jR5TR9gMsTNTWGjo6aGPZnvvPx",
"maxTimeoutSeconds": 0,
"extra": {
"feePayer": "2sNna5GLGutRVAH4ZoUgWxtz31gXKsRTFs6mWmvRmAg4"
}
}
}
}'

Amount unit note: The amount/value in all examples are in the token's smallest unit (not human-readable decimals). For a 6-decimal token: 1111 = 0.001111, 100 = 0.0001, 1000 = 0.001.

Response example

Success:

{
"code": 0,
"msg": "",
"data": {
"isValid": true,
"payer": "0x9F7236e6B4AAd75603C0DdB28dE5f12DeDe6E9D4"
},
"timestamp": 1769593299
}

Fail:

{
"code": 200,
"msg": "",
"data": {
"isValid": false,
"invalidReason": "nonce already used"
},
"timestamp": 1768997783
}

Error Codes

Error CodeConstant NameDescription
0CodeSuccessSuccess
51001CodeInvalidPayloadPayment payload invalid or missing
51002CodeInvalidRequirementsPayment requirements invalid or missing
51003CodeMissingPayloadFieldMissing payload field
51101CodeUnsupportedNetworkUnsupported network
51201CodeTokenNotFoundToken not found
51301CodeInvalidExactPayloadInvalid exact payload format
51302CodeMissingSignatureMissing signature
51401CodeRecipientMismatchRecipient address mismatch
51402CodeInvalidAuthValueInvalid auth value format
51403CodeInvalidRequiredAmountInvalid required amount format
51404CodeInsufficientAmountInsufficient amount
51502CodeNonceAlreadyUsedNonce already used
51602CodeInsufficientBalanceInsufficient balance
51701CodeInvalidSignatureFormatInvalid signature format
51702CodeInvalidSignatureLengthInvalid signature length (should be 65 bytes)
51704CodeInvalidSignatureInvalid signature (signature verification failed)
51901CodeInvalidValueFormatInvalid value format
51902CodeInvalidValidAfterFormatInvalid validAfter format
51903CodeInvalidValidBeforeFormatInvalid validBefore format
51904CodeInvalidNonceFormatInvalid nonce format
51905CodeInvalidNonceLengthInvalid nonce length (should be 32 bytes)

Permit2 / Solana Supplementary Notes (SDK Error Reasons)

In the current repository, new Permit2 / Solana errors are primarily returned as invalidReason / errorReason strings at the SDK layer, rather than new 51xxx numeric error codes.

Permit2 (EVM) Common Error Reasons (Examples)

FieldExample ValueDescription
invalidReasoninvalid_exact_evm_authorization_valuePermit2 authorization fields (e.g. nonce/deadline/amount) have invalid format
invalidReasoninvalid_exact_evm_nonce_already_usedNonce already used (replay)
invalidReasoninvalid_exact_evm_signaturePermit2 signature verification failed
invalidReasoninvalid_exact_evm_recipient_mismatchwitness.to does not match payTo
errorReasoninvalid_exact_evm_verification_failedPre-settle verify did not pass

Solana (SVM) Common Error Reasons (Examples)

FieldExample ValueDescription
invalidReasoninvalid_exact_solana_payload_missing_fee_payerMissing feePayer
invalidReasoninvalid_exact_solana_fee_payer_not_managed_by_facilitatorfeePayer is not a facilitator-managed address
invalidReasoninvalid_exact_solana_payload_transaction_could_not_be_decodedTransaction body cannot be decoded / invalid format
invalidReasoninvalid_exact_solana_payload_transaction_instructions_lengthInstruction count does not match expected
invalidReasoninvalid_exact_solana_payload_transaction_instructions_compute_price_instruction_too_highCompute unit price exceeds limit
invalidReasoninvalid_exact_solana_payload_recipient_mismatchRecipient address mismatch
invalidReasoninvalid_exact_solana_payload_amount_insufficientTransaction amount insufficient
errorReasoninvalid_exact_solana_transaction_failedOn-chain settlement transaction failed
errorReasoninvalid_exact_solana_transaction_confirmation_failedTransaction confirmation failed (may include blockhash expiry and other on-chain reasons)

Guidelines (SDK & Demo)

This section supplements the minimum runnable setup for the Go / TypeScript SDK and lists the ready-to-run Permit2 (EVM) and Solana (SVM) demos in the repository, making it easy to run an end-to-end flow directly.

Reference SDK Capabilities

The x402 official reference SDK is designed around the core goal of being "extensible and configurable."

EVM Support (@x402/evm)

@x402/evm supports any EVM-compatible chain you configure, and covers ERC-20 payments through two transfer methods:

  • EIP-3009 (Transfer With Authorization): For tokens that natively implement EIP-3009 (e.g. USDC). The buyer signs an authorization offline; the facilitator executes the transfer on-chain on their behalf, so the buyer does not need to do an on-chain approve first.
  • Permit2: For any ERC-20. The buyer signs a PermitWitnessTransferFrom message, and the facilitator executes the transfer.

This means coverage for:

  • Any Ethereum L1 / L2
  • Any EVM-compatible chain with a valid chain ID
  • Any ERC-20 (via Permit2) or EIP-3009-compatible token (USDC, etc.)

Permit2 Authorization (Approval)

Permit2 requires the buyer to have a valid prior authorization to the Permit2 contract. x402 supports two Gas Sponsorship extensions to handle this step automatically:

  • EIP-2612 Gas Sponsoring: For tokens that implement EIP-2612 (permit), the facilitator can pay Gas to complete the authorization to Permit2 based on an offline-signed permit message, so the buyer needs no Gas.

If Gas Sponsorship extensions are not enabled, the buyer must manually complete one "payment token → Permit2 contract" approve before their first payment.

Both EIP-3009 and Permit2 (including Gas Sponsorship extensions) are supported in the official TypeScript (@x402/evm) / Go SDK.

Solana Support (@x402/svm)

@x402/svm supports any Solana cluster, covering:

  • SPL Token Program tokens
  • Token2022 Program tokens

Demo (Runnable Directly from Repository)

# Install dependencies in the repository root
pnpm i

# Start (launches a local server and runs the client in the same process)
pnpm -C examples/typescript/clients/permit2_exact_bsc_flow start

Common environment variables (replace with your actual wallet/test chain values):

  • EVM_PRIVATE_KEY: Required — payer's EVM private key

  • GATE_WEB3_API_KEY / GATE_WEB3_API_SECRET: Required — facilitator (Gate Web3 OpenAPI) authentication

  • EVM_NETWORK: Optional — defaults to bsc

  • PERMIT_NONCE: Optional; if omitted, the demo auto-generates one to avoid nonce already used

  • Solana (devnet, exact) all-in-one server+client: examples/typescript/clients/svm_exact_solana_flow/

pnpm i
pnpm -C examples/typescript/clients/svm_exact_solana_flow start

Common environment variables:

  • SVM_CLIENT_PRIVATE_KEY: Required — Solana private key (base58)
  • SVM_PAYEE_ADDRESS: Required — recipient address (base58)
  • SVM_NETWORK: Optional — defaults to solana-devnet (recommended to use this value directly)
  • SVM_ASSET_MINT: Optional — defaults to devnet asset mint
  • SVM_FEE_PAYER: Required (workaround). When the current facilitator's /supported does not return feePayer/signers, you must provide this explicitly.
    • Testnet (solana-devnet) example: 2sNna5GLGutRVAH4ZoUgWxtz31gXKsRTFs6mWmvRmAg4
    • Mainnet (solana) example: ejyfDKF3YAgtVUcpEUdvNmhuSF2dcTdUMPRCfAmBL1V
  • GATE_WEB3_API_KEY / GATE_WEB3_API_SECRET: Required — facilitator authentication

Solana Network Name Compatibility (V1 / V2)

To avoid network not supported errors caused by inconsistent network names, use the values in the table below:

ScenarioRecommended Value
Inside the SDK (Go / TypeScript demo)solana-devnet (testnet), solana (mainnet)
Direct Gate OpenAPI calls (x402.verify / x402.settle)solana-devnet (testnet), solana (mainnet)

Note: Different naming conventions (e.g. CAIP-2 or other aliases) may appear in older versions. If you encounter compatibility issues, prioritize the values in the table above.

Go

  • Permit2 (BSC, exact) all-in-one demo: examples/go/permit2_exact_bsc_flow/
  • Solana (devnet, exact) all-in-one demo: examples/go/svm_exact_solana_flow/
cd examples/go/svm_exact_solana_flow
go run .

Payment case

This guide will show you how to create a Go client that can initiate paid requests to x402-protected resources.

TypeScript Integration (Payment)

For the minimum runnable TypeScript example, refer directly to:

Run commands:

pnpm -C examples/typescript/clients/permit2_exact_bsc_flow start
pnpm -C examples/typescript/clients/svm_exact_solana_flow start

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

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"
x402http "github.com/gatechain/x402/go/http"
evm "github.com/gatechain/x402/go/mechanisms/evm/exact/client"
evmsigners "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:

  1. Detects 402 Responses: When the server responds with 402 Payment Required, the client extracts payment requirements from the PAYMENT-REQUIRED header.
  2. Creates Payment Payload: The client creates a signed payment payload using the registered payment scheme.
  3. Retries with Payment: The client automatically retries the request with the PAYMENT-SIGNATURE header containing the payment payload (v2 standard naming).
  4. Handles Settlement: After successful payment verification, the server returns the resource and includes settlement confirmation in the PAYMENT-RESPONSE header.

Note: The x402 v2 standard headers are PAYMENT-REQUIRED / PAYMENT-SIGNATURE / PAYMENT-RESPONSE. Any X-PAYMENT-* occurrences in code are typically used only for legacy compatibility reading.

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.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.

TypeScript Integration (Receiving Payment)

The TypeScript receiving side (resource service) can also directly reuse the server portion of the all-in-one demo:

If you need separate deployment, you can extract the Express server portion from the above files; the client portion is only for local integration testing.

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

2. Set Environment Variables

Set the required environment variables before running the server:

# Required: Wallet address to receive payments
export PAYEE_ADDRESS="0x1234567890123456789012345678901234567890"

# Recommended: pair NETWORK and FACILITATOR_URL to avoid mixing testnet/mainnet
export NETWORK="gatelayer_testnet"
export FACILITATOR_URL="https://openapi-test.gateweb3.cc/api/v1/x402"

# 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"

Environment matching recommendations:

  • Test environment: NETWORK=gatelayer_testnet + FACILITATOR_URL=https://openapi-test.gateweb3.cc/api/v1/x402
  • Production environment: Choose mainnet based on business needs (e.g. eth / base / bsc) + FACILITATOR_URL=https://openapi.gateweb3.cc/api/v1/x402

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"
x402 "github.com/gatechain/x402/go"
x402http "github.com/gatechain/x402/go/http"
ginmw "github.com/gatechain/x402/go/http/gin"
evm "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(getenv("NETWORK", "gatelayer_testnet"))
facilitatorURL := getenv("FACILITATOR_URL", "https://openapi-test.gateweb3.cc/api/v1/x402")

fmt.Printf("🚀 Starting x402 payment server...\n")
fmt.Printf(" Payee address: %s\n", payTo)
fmt.Printf(" Network: %s\n", network)
fmt.Printf(" Facilitator: %s\n\n", facilitatorURL)

r := gin.Default()

// Create facilitator client
// Keep NETWORK and FACILITATOR_URL in the same environment tier
// (testnet with openapi-test, mainnet with openapi).
// 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: facilitatorURL,
})

// 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)
}
}

func getenv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}

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.

User Agreement

https://web3.gate.com/api-service-agreement

Last updated on 2026/03/27