Skip to content

Commit 5ac8746

Browse files
authored
Merge pull request 0xPolygon#2703 from 0xPolygon/x402-support
adds x402 starter material
2 parents d88638e + 307df18 commit 5ac8746

File tree

3 files changed

+350
-0
lines changed

3 files changed

+350
-0
lines changed

docs/pos/payments/x402/overview.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# x402 on Polygon
2+
3+
x402 is an open payment protocol that brings blockchain payments
4+
into a familiar web standard. By re-using the HTTP `402 Payment Required`
5+
status code, it lets developers handle on-chain and agentic payments with
6+
the same tools they already use for APIs and web services.
7+
8+
Instead of building complex wallet integrations or subscription systems,
9+
**developers can simply treat payments like another part of the HTTP request/response
10+
cycle.** This lowers the barrier for web2 developers experimenting with crypto,
11+
while also giving web3 builders a lightweight way to support pay-per-use APIs,
12+
agent-to-agent transactions, and micropayments.
13+
14+
[Read more about the x402 architecture and concepts here.](https://x402.gitbook.io/x402)
15+
16+
## Access on Polygon
17+
18+
Polygon currently supports x402 on Mainnet and Amoy through the following facilitators:
19+
20+
1. [x402.rs Facilitator Endpoint](https://facilitator.x402.rs/)
21+
2. [ThirdWeb](https://playground.thirdweb.com/payments/x402)
22+
3. Polygon Testnet Facilitator: https://x402-amoy.polygon.technology
23+
24+
Please note: For mainnet access through Polygon's Facilitator,
25+
reach out for [access here.](https://t.me/PolygonHQ/32)
26+
27+
The following guides will show how to use x402 on Polygon.
28+
The x402 community also has
29+
created [multiple examples](https://github.com/coinbase/x402/tree/main/examples/typescript)
30+
which can be easily adapted for Polygon.
31+
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Quickstart for Buyers
2+
3+
This guide will walk you how to use x402 on Polygon
4+
to interact with services that require payment.
5+
6+
By the end of this guide, you will be able to programmatically discover
7+
payment requirements, complete a payment, and access a paid resource.
8+
9+
## Prerequisites
10+
Before you begin, ensure you have:
11+
12+
* Metamask, Rabby or any wallet that support Polygon with USDC
13+
14+
* [Node.js](https://nodejs.org/en) and npm
15+
16+
## 1. Install Dependencies
17+
18+
**HTTP Clients**
19+
20+
Install [x402-axios](https://www.npmjs.com/package/x402-axios) or [x402-fetch](https://www.npmjs.com/package/x402-fetch):
21+
22+
```bash
23+
npm install x402-axios
24+
# or
25+
npm install x402-fetch
26+
```
27+
";
28+
29+
## 2. Create a Wallet Client
30+
31+
Create a wallet client using a tool like [viem](https://viem.sh/):
32+
33+
34+
```bash
35+
npm install viem
36+
```
37+
38+
Then, instantiate the wallet account and client:
39+
40+
```typescript
41+
import { wrapFetchWithPayment, decodeXPaymentResponse } from "x402-fetch";
42+
import { createWalletClient, http } from 'viem';
43+
import { privateKeyToAccount } from 'viem/accounts';
44+
import { polygonAmoy } from 'viem/chains';
45+
import 'dotenv/config';
46+
47+
const privateKey = process.env.PRIVATE_KEY;
48+
if (!privateKey) {
49+
throw new Error("PRIVATE_KEY not set in .env file");
50+
}
51+
52+
const account = privateKeyToAccount(`0x${privateKey}`);
53+
const client = createWalletClient({
54+
account,
55+
chain: polygonAmoy,
56+
transport: http()
57+
});
58+
59+
console.log("Using wallet address:", account.address);
60+
```
61+
62+
## 3. Make Paid Requests Automatically
63+
64+
You can use either `x402-fetch` or `x402-axios` to automatically handle 402 Payment Required responses and complete payment flows.
65+
66+
!!! info x402-fetch
67+
**x402-fetch** extends the native `fetch` API to handle 402 responses and payment headers for you. [Full example here](https://github.com/AkshatGada/x402_Polygon/tree/feature/facilitator-amoy/demo/quickstart-local)
68+
69+
```typescript
70+
import { wrapFetchWithPayment, decodeXPaymentResponse } from "x402-fetch";
71+
// other imports...
72+
73+
// wallet creation logic...
74+
75+
const FACILITATOR_URL = process.env.FACILITATOR_URL || "https://x402-amoy.polygon.technology"
76+
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
77+
78+
const url = process.env.QUICKSTART_RESOURCE_URL || 'http://127.0.0.1:4021/weather';
79+
80+
fetchWithPayment(url, { //url should be something like https://api.example.com/paid-endpoint
81+
method: "GET",
82+
})
83+
.then(async response => {
84+
const body = await response.json();
85+
console.log('Response body:', body);
86+
87+
// Only try to decode payment response if we got the weather data (not the 402 response)
88+
if (body.report) {
89+
console.log('All response headers:', Object.fromEntries(response.headers.entries()));
90+
const rawPaymentResponse = response.headers.get("x-payment-response");
91+
console.log('Raw x-payment-response:', rawPaymentResponse);
92+
93+
try {
94+
const paymentResponse = decodeXPaymentResponse(rawPaymentResponse);
95+
console.log('Decoded payment response:', paymentResponse);
96+
} catch (e) {
97+
console.error('Error decoding payment response:', e);
98+
console.error('Failed to decode response:', rawPaymentResponse);
99+
throw e;
100+
}
101+
}
102+
})
103+
.catch(async error => {
104+
console.error('Error:', error.message);
105+
if (error.response) {
106+
try {
107+
const text = await error.response.text();
108+
console.error('Response text:', text);
109+
console.error('Response status:', error.response.status);
110+
console.error('Response headers:', error.response.headers);
111+
} catch (e) {
112+
console.error('Error reading response:', e);
113+
console.error('Raw error:', error);
114+
}
115+
} else {
116+
console.error('Raw error:', error);
117+
}
118+
});
119+
```
120+
121+
## 4. Error Handling
122+
Clients will throw errors if:
123+
124+
* The request configuration is missing
125+
126+
* A payment has already been attempted for the request
127+
128+
* There is an error creating the payment header
129+
130+
## Summary
131+
* Install an x402 client package
132+
133+
* Create a wallet client
134+
135+
* Use the provided wrapper/interceptor to make paid API requests
136+
137+
* Payment flows are handled automatically for you
138+
139+
## References:
140+
141+
* [x402-fetch npm docs](https://www.npmjs.com/package/x402-fetch)
142+
143+
* [x402-axios npm docs](https://www.npmjs.com/package/x402-axios)
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Quickstart for Sellers
2+
3+
This guide walks you through integrating with x402
4+
to enable payments for your API or service. By the end,
5+
your API will be able to charge buyers and AI agents for access.
6+
7+
## Prerequisites
8+
9+
Before you begin, ensure you have:
10+
11+
* A crypto wallet to receive funds (any EVM-compatible wallet)
12+
* [Node.js](https://nodejs.org/en) and npm (or Python and pip) installed
13+
* An existing API or server
14+
15+
**Note**
16+
17+
There are pre-configured examples available in the Coinbase repo for
18+
[Node.js](https://github.com/coinbase/x402/tree/main/examples/typescript/servers).
19+
There is also an [advanced example](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/advanced)
20+
that shows how to use the x402 SDKs to build a more complex payment flow.
21+
The following example shows how to adapt these for Polygon.
22+
23+
## 1. Install Dependencies
24+
25+
Install the [x402 Express middleware package](https://www.npmjs.com/package/x402-express).
26+
27+
```bash
28+
npm install x402-express
29+
```
30+
31+
Install the [x402 Next.js middleware package](https://www.npmjs.com/package/x402-next).
32+
33+
```bash
34+
npm install x402-next
35+
```
36+
37+
```bash
38+
npm install x402-hono
39+
```
40+
41+
### 2. Add Payment Middleware
42+
43+
Integrate the payment middleware into your application. You will need
44+
to provide:
45+
46+
* The Facilitator URL or facilitator object. For testing,
47+
use `https://facilitator.x402.rs/` which works on Polygon Mainnet and Amoy.
48+
* For a facilitator access on Polygon, please contact us [here.](https://t.me/PolygonHQ/32)
49+
* The routes you want to protect.
50+
* Your receiving wallet address.
51+
52+
53+
Full example in the repo [here](https://github.com/AkshatGada/x402_Polygon/tree/feature/facilitator-amoy/demo/quickstart-local).
54+
55+
56+
57+
```javascript
58+
import express from "express";
59+
import { paymentMiddleware } from "x402-express";
60+
61+
const app = express();
62+
63+
app.use(paymentMiddleware(
64+
"0xCA3953e536bDA86D1F152eEfA8aC7b0C82b6eC00", // receiving wallet address
65+
{ // Route configurations for protected endpoints
66+
"GET /weather": {
67+
// USDC amount in dollars
68+
price: "$0.001",
69+
network: "polygon-amoy",
70+
// Optional: Add metadata for better discovery in x402 Bazaar
71+
config: {
72+
description: "Get current weather data for any location",
73+
inputSchema: {
74+
type: "object",
75+
properties: {
76+
location: { type: "string", description: "City name" }
77+
}
78+
},
79+
outputSchema: {
80+
type: "object",
81+
properties: {
82+
weather: { type: "string" },
83+
temperature: { type: "number" }
84+
}
85+
}
86+
}
87+
},
88+
},
89+
{
90+
url: process.env.FACILITATOR_URL || "https://facilitator.x402.rs", // Polygon Amoy facilitator
91+
}
92+
));
93+
94+
// Implement your route
95+
app.get("/weather", (req, res) => {
96+
res.send({
97+
report: {
98+
weather: "sunny",
99+
temperature: 70,
100+
},
101+
});
102+
});
103+
104+
app.listen(4021, () => {
105+
console.log(`Server listening at http://localhost:4021`);
106+
});
107+
```
108+
109+
Full example in the repo [here](https://github.com/AkshatGada/x402_Polygon/tree/feature/facilitator-amoy/demo/quickstart-local).
110+
Since this is a fullstack example, we recommend using the example to build
111+
this yourself, and treat the code snippet below as a reference to adapt for
112+
Polygon.
113+
114+
```javascript
115+
import { paymentMiddleware, Network } from 'x402-next';
116+
117+
// Configure the payment middleware
118+
export const middleware = paymentMiddleware(
119+
"0xYourAddress", // your receiving wallet address
120+
{ // Route configurations for protected endpoints
121+
'/protected': {
122+
price: '$0.01',
123+
network: "polygon-amoy",
124+
config: {
125+
description: 'Access to protected content'
126+
}
127+
},
128+
}
129+
{
130+
url: "https://facilitator.x402.rs/", // Facilitator URL for Polygon testnet and mainnet
131+
}
132+
);
133+
134+
// Configure which paths the middleware should run on
135+
export const config = {
136+
matcher: [
137+
'/protected/:path*',
138+
]
139+
};
140+
```
141+
142+
143+
144+
```javascript
145+
import { Hono } from "hono";
146+
import { paymentMiddleware, Network } from "x402-hono";
147+
148+
const app = new Hono();
149+
150+
// Configure the payment middleware
151+
app.use(paymentMiddleware(
152+
"0xYourAddress",
153+
{
154+
"/protected-route": {
155+
price: "$0.01",
156+
network: "polygon-amoy",
157+
config: {
158+
description: "Access to premium content",
159+
}
160+
}
161+
},
162+
{
163+
url: 'https://facilitator.x402.rs' // 👈 Facilitator URL
164+
}
165+
));
166+
167+
// Implement your route
168+
app.get("/protected-route", (c) => {
169+
return c.json({ message: "This content is behind a paywall" });
170+
});
171+
172+
serve({
173+
fetch: app.fetch,
174+
port: 3000
175+
});
176+
```

0 commit comments

Comments
 (0)