Skip to main content

How to use Credit

Credit Mode pre-charges USDC and deducts credits off-chain each time you call an API. Because no on-chain transaction occurs per request, you incur no gas fees — making this mode well-suited for high-frequency calls and predictable workloads.

Implementation follows these 5 steps.

  1. SIWx Authentication → JWT Issuance — Sign a message with your wallet and receive a JWT.
  2. Call API — Call the API with the JWT in the header. Credits are deducted off-chain if the balance is sufficient.
  3. Charge Credits — If the balance is insufficient, receive a 402 response, generate a PAYMENT-SIGNATURE, and charge credits.
  4. Retry API Call — After charging, call the same API again in the same way.
  5. Check Balance — Query the current credit balance.

Step 1. SIWx Authentication​

Before calling the API, issue a JWT through wallet-signature-based authentication (SIWx). Sign a message with your private key and submit it to POST /auth to receive a JWT. The issued JWT is valid for 1 hour and is used in the Authorization header for all subsequent API calls.

Step 1-1. Compose SIWx Message​

For EVM wallets, compose a SIWE message in the format below. Join each line with \n.

SIWE Message Template
{DOMAIN} wants you to sign in with your Ethereum account:
{WALLET_ADDRESS}

Sign in to x402.nodit.io

URI: https://x402.nodit.io
Version: 1
Chain ID: {CHAIN_ID}
Nonce: {NONCE}
Issued At: {ISO_8601}
Expiration Time: {ISO_8601_PLUS_10MIN}
  • {DOMAIN}: The domain requesting the signature (e.g., x402.nodit.io)
  • {WALLET_ADDRESS}: The EVM wallet address used for signing
  • {CHAIN_ID}: The Chain ID of the network used for payment (e.g., Base Mainnet → 8453)
  • {NONCE}: A 16-byte random hex string to prevent replay attacks
  • {ISO_8601}: The ISO 8601 timestamp at the time of signing (e.g., 2025-01-01T00:00:00Z)
  • {ISO_8601_PLUS_10MIN}: The expiration time, 10 minutes after the signing timestamp

Joining each line of the template above with \n produces the following string.

SIWE Message Example
x402.nodit.io wants you to sign in with your Ethereum account:\n0xAbC1234567890DEF1234567890AbCdEf12345678\n\nSign in to x402.nodit.io\n\nURI: https://x402.nodit.io\nVersion: 1\nChain ID: 8453\nNonce: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\nIssued At: 2025-01-01T00:00:00Z\nExpiration Time: 2025-01-01T00:10:00Z

Step 1-2. Sign Message​

Sign the composed message with your private key. The signing method differs by chain.

ChainSigning MethodSignature Format
EVMwallet.signMessage(message) (EIP-191 personal_sign)Hex string
Solananacl.sign.detached(messageBytes, secretKey)Base58-encoded string

The signature is used in the signature field of the POST /auth request in the next step.

Step 1-3. Issue JWT​

Send the message and signature to POST /auth to receive a JWT in the accessToken field.

POST /auth — Request Body
{
"message": "{SIWE_OR_SIWS_MESSAGE}",
"signature": "{SIGNATURE}"
}
POST /auth — Response
{
"accessToken": "{JWT}"
}

Step 2. Call API​

After issuing a JWT, attach it to the Authorization header and call the API. If the credit balance is sufficient, credits are deducted off-chain and the API response is returned.

API TypeURL Pattern
Web3 Data API/credit/v1/{CHAIN}/{NETWORK}/{CATEGORY}/{METHOD}
Node API (JSON-RPC)/credit/{CHAIN}/{NETWORK}/json-rpc

The following is an example of a Web3 Data API call.

Web3 Data API Request Example
curl --request POST \
--url https://x402.nodit.io/credit/v1/ethereum/mainnet/blockchain/getBlockByHashOrNumber \
--header 'Authorization: Bearer {JWT}' \
--header 'Content-Type: application/json' \
--data '{"block": "latest"}'

If the balance is sufficient, credits are deducted and a 200 response is returned. If the balance is insufficient, a 402 Payment Required response is returned. In that case, charge credits following Step 3 below, then retry the same request.


Step 3. Charge Credits​

When the balance is insufficient, the API returns 402 Payment Required. Send a charge request to receive payment terms, generate a PAYMENT-SIGNATURE, and submit the retry request to charge credits. The minimum charge amount is 0.01 USDC (10,000 atomic units).

Step 3-1. Request Charge — Receive 402​

Send a charge request as shown below. The server returns 402 Payment Required.

POST /credit/charge — Initial Request
curl --request POST \
--url https://x402.nodit.io/credit/charge \
--header 'Authorization: Bearer {JWT}' \
--header 'Content-Type: application/json' \
--data '{"amount": "1000000"}'
402 Response
HTTP/1.1 402 Payment Required
Content-Type: application/json
PAYMENT-REQUIRED: eyJ4NDAyV...

Step 3-2. Select Payment Network​

Base64-decode the PAYMENT-REQUIRED header and select the accept object for the network you want to use for payment.

Decode PAYMENT-REQUIRED Header
const paymentRequired = JSON.parse(
Buffer.from(res402.headers['payment-required'], 'base64').toString()
);

The decoded accepts array looks like the following.

PAYMENT-REQUIRED Decoded Example
{
"x402Version": 2,
"accepts": [
{
"network": "eip155:8453",
"asset": "0x...",
"payTo": "0x...",
"amount": "1000000",
"maxTimeoutSeconds": 3600,
"scheme": "exact",
"extra": { "name": "USDC", "version": "2" }
},
{
"network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"asset": "...",
"payTo": "...",
"amount": "1000000",
"scheme": "exact",
"extra": { "name": "USDC", "version": "1", "feePayer": "..." }
}
]
}

Step 3-3. Generate PAYMENT-SIGNATURE​

The signing method differs by the selected network. After signing, compose the payload in the JSON structure below and base64-encode it.

Sign using EIP-3009 TransferWithAuthorization.

EVM PAYMENT-SIGNATURE
{
"x402Version": 2,
"resource": { "url": "https://x402.nodit.io/credit/charge", "description": "Credit charge", "mimeType": "application/json" },
"accepted": { "network": "{NETWORK}", "asset": "{ASSET_ADDRESS}", "payTo": "{PAYTO_ADDRESS}", "amount": "{AMOUNT}", "scheme": "exact", "extra": { "name": "USDC", "version": "{VERSION}" } },
"payload": {
"signature": "{EIP_712_SIGNATURE}",
"authorization": {
"from": "{WALLET_ADDRESS}",
"to": "{PAYTO_ADDRESS}",
"value": "{AMOUNT}",
"validAfter": "0",
"validBefore": "{VALID_BEFORE}",
"nonce": "{NONCE}"
}
}
}
Reference

For details on generating the signature, see the EIP-3009 specification.

PAYMENT-SIGNATURE Expiration

The PAYMENT-SIGNATURE is valid for 300 seconds. Submit the retry request within this window after generating the signature.

Step 3-4. Retry with PAYMENT-SIGNATURE​

Base64-encode the composed payload, attach it to the payment-signature header, and submit the retry request.

POST /credit/charge — with PAYMENT-SIGNATURE
curl --request POST \
--url https://x402.nodit.io/credit/charge \
--header 'Authorization: Bearer {JWT}' \
--header 'Content-Type: application/json' \
--header 'PAYMENT-SIGNATURE: {BASE64_ENCODED_PAYMENT_PAYLOAD}' \
--data '{"amount": "1000000"}'

When the charge completes, the response returns the updated balance and transaction hash.

Charge Response
{
"balance": 1000000,
"paymentResponse": { "txHash": "{TX_HASH}" }
}

Step 4. Retry API Call​

After the charge completes, call the API again in the same way as Step 2. The charged credits are deducted off-chain and a 200 response is returned.

Retry API Request
curl --request POST \
--url https://x402.nodit.io/credit/v1/ethereum/mainnet/blockchain/getBlockByHashOrNumber \
--header 'Authorization: Bearer {JWT}' \
--header 'Content-Type: application/json' \
--data '{"block": "latest"}'

Step 5. Check Balance​

Query the current credit balance via GET /credit/balance. Attach the JWT to the Authorization header.

GET /credit/balance
curl --request GET \
--url https://x402.nodit.io/credit/balance \
--header 'Authorization: Bearer {JWT}'
Balance Response
{
"balance": 1000000
}

info

For Pay-Per-Use Mode, which settles each request on-chain without pre-charging, see How to use Pay-Per-Use.