| name | x402-pharos |
| description | x402 payment protocol for Pharos (mainnet & testnet). Use when building paid APIs, monetizing endpoints, or integrating crypto payments on Pharos. Triggers on "x402 pharos", "paid API pharos", "pharos payment", "payment gateway pharos". |
| license | MIT |
| metadata | {"author":"antdigital","version":"1.0.0"} |
x402 Pharos Payment Protocol
x402 is an open standard for HTTP-native payments, adapted for Pharos. This skill supports both Pharos Pacific Mainnet and Pharos Atlantic Testnet — default to mainnet unless the user asks for testnet.
Pharos Network
| Parameter | Pacific Mainnet (default) | Atlantic Testnet |
|---|
| Chain ID | 1672 | 688689 |
| Network Identifier | eip155:1672 | eip155:688689 |
| RPC URL | https://rpc.pharos.xyz | https://atlantic.dplabs-internal.com |
| USDC Address | 0xYourTokenAddress (provided by user) | 0xYourTokenAddress (provided by user) |
| Facilitator URL | provided by user | provided by user |
Which network to use: Use Pacific Mainnet (1672) by default. Only switch to Atlantic Testnet (688689) when the user explicitly asks to build/test on testnet. When generating code, substitute the matching Chain ID, Network Identifier, and RPC URL from the table above — everything else stays the same.
When to Use
- Building paid APIs on Pharos (mainnet or testnet)
- Adding payment requirements to existing services
- Creating AI agents that can pay for API access using USDC
- Integrating crypto payments into web applications on Pharos
Quick Start
Server Setup
mkdir my-x402-server && cd my-x402-server
npm init -y
npm install @x402/core @x402/express @x402/evm @x402/fetch express viem typescript tsx @types/node @types/express dotenv
npx tsc --init --esModuleInterop --moduleResolution node --module esnext --target es2022
Create .env file:
PAY_TO_ADDRESS=0x your receiving address
PORT=4021
FACILITATOR_URL=http://xxx your facilitator url
USDC_ADDRESS=0xYourTokenAddress
USDC_NAME=USDC
Run the server:
npx tsx server.ts
⚠️ Important: Make sure to run commands from the project directory. If you encounter ERR_MODULE_NOT_FOUND errors, verify:
node_modules is installed in the current directory (not parent directory)
- You are running
npx tsx server.ts from the same directory where you ran npm install
- Run
npm install again in the current directory if needed
Client Setup
mkdir my-x402-client && cd my-x402-client
npm init -y
npm install @x402/core @x402/fetch @x402/evm viem dotenv tsx typescript @types/node
Create .env file:
EVM_PRIVATE_KEY=0x your private key here
SERVER_URL=http://localhost:4021
Run the client:
npx tsx client.ts http://localhost:4021/data
Configuration
Environment Variables
Client:
EVM_PRIVATE_KEY: Private key (set via environment variable or file)
SERVER_URL: Server url
Server:
PAY_TO_ADDRESS: Receiving address
PORT: Server port (optional)
FACILITATOR_URL: Facilitator address
USDC_ADDRESS: USDC token address
USDC_NAME: USDC token name (optional, defaults to "USDC")
Security Best Practices
❌ Don't do:
- Don't write private keys directly in code
- Don't commit private keys to version control
- Don't log private keys
✅ Recommended practices:
- Use environment variables for private keys
- Use
.private_key file (added to .gitignore)
- Use
.env file (added to .gitignore)
Complete Code Examples
The examples below target Pacific Mainnet (eip155:1672). To target Atlantic Testnet, replace every eip155:1672 with eip155:688689, chainId: 1672 with 688689, pharos-mainnet with pharos-testnet, and the rpcUrl with https://atlantic.dplabs-internal.com — see the network table above.
Server (Seller) - Monetize Your API
import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";
import { config } from "dotenv";
config();
const payToAddress = process.env.PAY_TO_ADDRESS as `0x${string}`;
if (!payToAddress) {
console.error('Please set PAY_TO_ADDRESS environment variable');
process.exit(1);
}
if (!payToAddress.startsWith('0x') || payToAddress.length !== 42) {
console.error('Invalid receiving address format');
process.exit(1);
}
const facilitatorUrl = process.env.FACILITATOR_URL;
const port = process.env.PORT || 4021;
const usdcAddress = process.env.USDC_ADDRESS;
const usdcName = process.env.USDC_NAME || "USDC";
if (!facilitatorUrl || !usdcAddress) {
console.error('Please set FACILITATOR_URL and USDC_ADDRESS');
process.exit(1);
}
const facilitatorClient = new HTTPFacilitatorClient({ url: facilitatorUrl });
const resourceServer = new x402ResourceServer(facilitatorClient);
const evmScheme = new ExactEvmScheme();
evmScheme.registerMoneyParser(async (amount, network) => {
if (network === "eip155:1672") {
return {
amount: (amount * 1e6).toString(),
asset: usdcAddress,
extra: {
token: usdcName,
name: usdcName,
version: "2"
}
};
}
return null;
});
resourceServer.register(
"eip155:1672",
evmScheme
);
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
paymentMiddleware(
{
"GET /data": {
accepts: {
scheme: "exact",
price: "0.001",
network: "eip155:1672",
payTo: payToAddress,
},
description: "Random data service",
mimeType: "application/json",
},
"GET /weather/:city": {
accepts: {
scheme: "exact",
price: "0.002",
network: "eip155:1672",
payTo: payToAddress,
},
description: "Weather data service",
mimeType: "application/json",
},
"POST /generate": {
accepts: {
scheme: "exact",
price: "0.005",
network: "eip155:1672",
payTo: payToAddress,
},
description: "AI generation service",
mimeType: "application/json",
},
},
resourceServer
)
);
app.get("/health", (req, res) => {
res.json({
status: "healthy",
timestamp: new Date().toISOString(),
network: "pharos-mainnet",
chainId: 1672,
usdcAddress: usdcAddress,
payToAddress: payToAddress,
});
});
app.get("/data", (req, res) => {
res.json({
message: "Hello, paid user!",
data: {
timestamp: Date.now(),
random: Math.random(),
network: "pharos-mainnet",
chainId: 1672,
},
payment: {
price: "0.001 USDC",
network: "eip155:1672",
},
});
});
app.get("/weather/:city", (req, res) => {
const city = req.params.city || "Shanghai";
const weatherData = {
city,
temperature: Math.floor(Math.random() * 30) + 10,
condition: ["Sunny", "Cloudy", "Light Rain", "Overcast"][Math.floor(Math.random() * 4)],
humidity: Math.floor(Math.random() * 40) + 40,
windSpeed: Math.floor(Math.random() * 20) + 5,
timestamp: new Date().toISOString(),
};
res.json({
weather: weatherData,
payment: {
price: "0.002 USDC",
network: "eip155:1672",
},
});
});
app.post("/generate", (req, res) => {
const { prompt, type = "text" } = req.body;
if (!prompt) {
return res.status(400).json({ error: "Prompt is required" });
}
const generated = {
id: Math.random().toString(36).substring(2, 15),
type,
prompt,
result: `Generated ${type} for: ${prompt}`,
tokens: Math.floor(Math.random() * 1000) + 100,
timestamp: new Date().toISOString(),
};
res.json({
generated,
payment: {
price: "0.005 USDC",
network: "eip155:1672",
},
});
});
app.get("/config", (req, res) => {
res.json({
network: {
name: "pharos-mainnet",
chainId: 1672,
rpcUrl: "https://rpc.pharos.xyz",
usdcAddress: usdcAddress,
facilitatorUrl: facilitatorUrl,
},
endpoints: [
{ path: "/health", price: "Free", description: "Health check" },
{ path: "/data", price: "0.001 USDC", description: "Random data" },
{ path: "/weather/:city", price: "0.002 USDC", description: "Weather data" },
{ path: "/generate", price: "0.005 USDC", description: "AI generation" },
],
payToAddress: payToAddress,
});
});
app.use((err: any, req: any, res: any, next: any) => {
console.error('Error:', err);
res.status(500).json({
error: 'Internal server error',
message: err.message
});
});
app.use((req, res) => {
res.status(404).json({ error: 'Endpoint not found' });
});
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});
Client (Buyer) - Call Paid APIs
import { wrapFetchWithPayment, x402Client, decodePaymentResponseHeader } from '@x402/fetch';
import { privateKeyToAccount } from 'viem/accounts';
import { config } from 'dotenv';
import fs from 'fs';
import { ExactEvmScheme } from '@x402/evm';
config();
const privateKey = process.env.EVM_PRIVATE_KEY ||
(fs.existsSync('.private_key') ? fs.readFileSync('.private_key', 'utf-8').trim() : null);
if (!privateKey) {
console.error('Please set EVM_PRIVATE_KEY or create .private_key file');
process.exit(1);
}
if (!privateKey.startsWith('0x')) {
console.error('Private key must start with 0x');
process.exit(1);
}
const signer = privateKeyToAccount(privateKey as `0x${string}`);
const client = new x402Client();
client.register("eip155:1672", new ExactEvmScheme(signer))
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
async function main() {
const serverUrl = process.argv[2];
if (!serverUrl) {
console.error('Please provide server URL');
process.exit(1);
}
const response = await fetchWithPayment(serverUrl);
const data = await response.json();
console.log(data);
}
main().catch(console.error);
package.json
{
"name": "x402-pharos-example",
"version": "2.1.0",
"type": "module",
"scripts": {
"server": "tsx server.ts",
"client": "tsx client.ts http://localhost:4021/data",
"dev:server": "tsx watch server.ts",
"dev:client": "tsx watch client.ts"
},
"dependencies": {
"@x402/core": "^2.0.0",
"@x402/express": "^2.0.0",
"@x402/fetch": "^2.0.0",
"@x402/evm": "^2.0.0",
"express": "^4.18.2",
"viem": "^2.0.0",
"dotenv": "^16.3.1"
},
"devDependencies": {
"@types/node": "^20.10.0",
"tsx": "^4.6.0",
"typescript": "^5.3.0"
}
}
Dynamic Pricing Example
{
"GET /ai/:model": {
accepts: (req) => ({
scheme: "exact",
price: req.params.model === "gpt4" ? "0.10" : "0.01",
network: "eip155:1672",
payTo: payToAddress,
}),
},
}
Payment Flow
- Client makes request to protected endpoint
- Server returns HTTP 402 with
PAYMENT-REQUIRED header
- Client parses requirements, signs payment
- Client re-sends request with
X-PAYMENT header
- Server forwards to Facilitator to verify
- Facilitator settles payment on-chain (USDC)
- Server returns response with
PAYMENT-RESPONSE header
Resources