Skip to content

Commit b7add11

Browse files
committed
feat: Implementing X402 agentic payment
1 parent a53e448 commit b7add11

23 files changed

Lines changed: 2105 additions & 327 deletions

File tree

README.md

Lines changed: 133 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,171 +1,177 @@
1-
# PLUTO API
1+
# PLUTO — Agentic Payment Infrastructure on Stellar
22

3-
Accept Stellar payments (XLM or Stellar assets like USDC) using simple payment links and a developer-friendly API.
3+
> **Hackathon submission for: Agents on Stellar · x402 + Stripe MPP**
44
5-
This project aims to feel like Stripe/PayPal, but built on Stellar. Merchants create a payment, share a link or QR code, and the API confirms the on-chain payment and notifies the merchant.
5+
PLUTO is a Stripe-like payment gateway built on Stellar that lets merchants accept XLM and USDC payments — now extended with **x402 pay-per-request** so AI agents can autonomously pay for API access using USDC micropayments.
66

7-
## What It Does
7+
---
88

9-
- Create payment intents with an amount, asset, and recipient
10-
- Generate a payment link (ready for QR code usage)
11-
- Verify payments on Stellar via Horizon
12-
- Track status in Supabase (pending → confirmed)
13-
- Send webhook notifications when payments are confirmed
9+
## What We Built
1410

15-
## Tech Stack
11+
### Core: Merchant Payment Gateway
12+
A full-stack payment infrastructure on Stellar testnet:
13+
- Merchants register and get an API key
14+
- Create payment links (`POST /api/create-payment`)
15+
- Customers pay via a branded checkout page (`/pay/:id`)
16+
- Payments confirmed automatically via Horizon polling
17+
- Webhooks fire on confirmation
18+
- Real-time dashboard with analytics
1619

17-
- Backend: Node.js + Express
18-
- Database: Supabase (Postgres)
19-
- Stellar: `stellar-sdk` + Horizon API
20-
- Frontend: Next.js + Tailwind (starter shell in `frontend/`)
20+
### New: x402 Agentic Payments
21+
The x402 protocol turns any HTTP endpoint into a pay-per-request service. AI agents can autonomously pay for API access without subscriptions or API keys — just USDC on Stellar.
2122

22-
## Prerequisites
23+
**Flow:**
24+
```
25+
Agent → GET /api/demo/protected
26+
← 402 { amount: "0.10", asset: "USDC", recipient: "G...", memo: "x402-abc123" }
27+
Agent → sends 0.10 USDC on Stellar with memo
28+
Agent → POST /api/verify-x402 { tx_hash, amount, recipient, memo }
29+
← { access_token: "eyJ..." }
30+
Agent → GET /api/demo/protected + X-Payment-Token: eyJ...
31+
← 200 { secret_data: "you paid for this" }
32+
```
2333

24-
- Node.js 20+
25-
- Redis (required for backend rate limiting)
26-
- Supabase project (URL, service role key, and Postgres connection string)
34+
---
2735

28-
## Quick Start (Backend)
36+
## Live Demo
2937

30-
1. Install dependencies:
31-
```bash
38+
### Run the agent demo
39+
```bash
3240
cd backend
33-
npm install
41+
node scripts/demoAgent.js
3442
```
3543

36-
2. Configure environment:
37-
```bash
38-
cp .env.example .env
39-
```
44+
Watch an AI agent go through the full payment loop — 402 → pay → verify → 200 — entirely automatically on Stellar testnet.
4045

41-
If you skip this, backend startup validation fails and prints missing required keys.
46+
### Frontend demo
47+
Visit `http://localhost:3000/x402-demo` to see the agent payment flow visualized in real-time.
4248

43-
Optional: bring up Redis quickly with Docker:
44-
```bash
45-
docker run --name stellar-redis -p 6379:6379 redis:7-alpine
46-
```
49+
---
4750

48-
Or install Redis locally (example with Homebrew):
49-
```bash
50-
brew install redis
51-
brew services start redis
52-
```
51+
## Tech Stack
5352

54-
3. Fill out `backend/.env`:
55-
```
56-
SUPABASE_URL=your_supabase_url
57-
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
58-
DATABASE_URL=your_supabase_transaction_pooler_uri
59-
REDIS_URL=redis://localhost:6379
60-
STELLAR_NETWORK=testnet
61-
# Optional overrides:
62-
STELLAR_HORIZON_URL=
63-
USDC_ISSUER=your_usdc_issuer
64-
PAYMENT_LINK_BASE=http://localhost:3000
65-
CREATE_PAYMENT_RATE_LIMIT_MAX=50
66-
CREATE_PAYMENT_RATE_LIMIT_WINDOW_MS=60000
67-
```
53+
| Layer | Tech |
54+
|-------|------|
55+
| Backend | Node.js + Express |
56+
| Database | Supabase (Postgres) |
57+
| Blockchain | Stellar SDK + Horizon API (testnet) |
58+
| Frontend | Next.js 14 + Tailwind CSS |
59+
| Real-time | Socket.io + SSE |
60+
| Rate limiting | Redis |
61+
| Agentic payments | x402 protocol (custom implementation) |
6862

69-
4. Apply schema in Supabase:
70-
- Run database migrations:
71-
```bash
72-
cd backend
73-
npm run migrate
74-
```
63+
---
7564

76-
5. Run the API:
77-
```bash
78-
npm run dev
79-
```
65+
## x402 Implementation
8066

81-
Or start Redis + API together from the backend folder:
82-
```bash
83-
docker compose up
67+
### New endpoints
68+
- `POST /api/verify-x402` — verifies a Stellar USDC payment and issues a short-lived JWT
69+
- `GET /api/demo/protected` — example paywalled endpoint (0.10 USDC per request)
70+
- `GET /api/demo/free` — free endpoint for comparison
71+
72+
### Middleware
73+
`backend/src/middleware/x402.js` — drop-in Express middleware that protects any route:
74+
75+
```js
76+
import { x402Middleware } from './middleware/x402.js';
77+
78+
app.get('/api/my-paid-endpoint',
79+
x402Middleware({ amount: '0.10', recipient: 'G...YOUR_ADDRESS' }),
80+
(req, res) => res.json({ data: 'you paid for this' })
81+
);
8482
```
8583

86-
API will be available at `http://localhost:4000`.
84+
### Replay attack prevention
85+
Every verified `tx_hash` is stored in the `x402_payments` table. Reusing a transaction hash returns `409 Conflict`.
86+
87+
### Access tokens
88+
Short-lived JWTs (60s expiry) signed with `X402_JWT_SECRET`. Agents include them as `X-Payment-Token` header on retries.
89+
90+
---
8791

88-
Rate limiting uses Redis-backed shared state, so multiple API instances behind a load balancer enforce the same counters.
92+
## Stellar Testnet Interaction
8993

90-
Generate a static OpenAPI asset for SDK generation or external docs:
94+
This project makes real Stellar testnet transactions:
95+
- Payment creation stores recipient Stellar addresses
96+
- Horizon polling confirms on-chain USDC/XLM payments
97+
- x402 agent submits real USDC payments on testnet
98+
- All transactions verifiable on [Stellar Expert (testnet)](https://stellar.expert/explorer/testnet)
99+
100+
USDC issuer (testnet): `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`
101+
102+
---
103+
104+
## Quick Start
105+
106+
### Prerequisites
107+
- Node.js 18+
108+
- Redis
109+
- Supabase account
110+
- Stellar testnet wallet (Freighter)
111+
112+
### Backend
91113
```bash
92114
cd backend
93-
npm run build:docs
115+
cp .env.example .env
116+
# Fill in SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, DATABASE_URL
117+
npm install
118+
npm run migrate
119+
npm run dev
94120
```
95121

96-
This writes `backend/public/openapi.json`.
122+
### Frontend
123+
```bash
124+
cd frontend
125+
cp .env.example .env.local
126+
# Set NEXT_PUBLIC_API_URL=http://localhost:4000
127+
npm install
128+
npm run dev
129+
```
97130

98-
Verify the XLM -> USDC path-payment flow on Stellar testnet without a wallet:
131+
### Run the x402 agent demo
99132
```bash
100133
cd backend
101-
npm run verify:path-payment:testnet
134+
node scripts/demoAgent.js
102135
```
103136

104-
This script creates disposable testnet accounts, issues a temporary USDC asset, places a DEX offer, discovers the best XLM -> USDC path, submits a live `path_payment_strict_receive`, and prints the transaction hash plus the recipient's received USDC amount.
105-
106-
## API Endpoints
107-
108-
- `GET /health`
109-
- `POST /api/create-payment`
110-
- `POST /api/sessions`
111-
- `GET /api/payment-status/:id`
112-
- `POST /api/verify-payment/:id`
113-
- `GET /api/merchant-branding`
114-
- `PUT /api/merchant-branding`
115-
116-
### Create Payment
117-
118-
```json
119-
{
120-
"amount": 50,
121-
"asset": "USDC",
122-
"asset_issuer": "G...ISSUER",
123-
"recipient": "G...RECIPIENT",
124-
"description": "Digital product",
125-
"webhook_url": "https://merchant.app/webhooks/stellar",
126-
"branding_overrides": {
127-
"primary_color": "#5ef2c0",
128-
"secondary_color": "#b8ffe2",
129-
"background_color": "#050608"
130-
}
131-
}
132-
```
137+
---
133138

134-
`POST /api/create-payment` and `POST /api/sessions` are rate-limited per API key. By default the backend allows 50 requests per 60 seconds and returns `429 Too Many Requests` with a `Retry-After` header when the limit is exceeded.
139+
## Environment Variables
135140

136-
Both endpoints return `branding_config` in the response. The config is resolved in this order:
137-
1) per-session `branding_overrides`
138-
2) merchant `branding_config`
139-
3) system defaults
141+
```env
142+
# Supabase
143+
SUPABASE_URL=
144+
SUPABASE_SERVICE_ROLE_KEY=
145+
DATABASE_URL=
140146
141-
### Verify Payment
147+
# Stellar
148+
STELLAR_NETWORK=testnet
149+
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
150+
USDC_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
142151
143-
`POST /api/verify-payment/:id` checks Horizon for a matching payment and, if found, marks it as confirmed and fires a webhook.
152+
# x402
153+
X402_JWT_SECRET=your_secret_here
154+
X402_TOKEN_EXPIRY_SECONDS=60
155+
X402_PROVIDER_PUBLIC_KEY=G...YOUR_PROVIDER_ADDRESS
144156
145-
Webhook payload:
146-
```json
147-
{
148-
"event": "payment.confirmed",
149-
"payment_id": "...",
150-
"amount": 50,
151-
"asset": "USDC",
152-
"asset_issuer": "G...ISSUER",
153-
"recipient": "G...RECIPIENT",
154-
"tx_id": "..."
155-
}
157+
# Redis
158+
REDIS_URL=redis://localhost:6379
156159
```
157160

158-
## Roadmap & Issues
161+
---
162+
163+
## What's Next
159164

160-
The project currently has a comprehensive roadmap of **100+ active issues** covering:
161-
- **Core Stellar Integrations**: SEP-0001, SEP-0010, Path Payments, etc.
162-
- **Backend Architecture**: Service layer refactor, Redis idempotency, API versioning.
163-
- **Frontend/UX**: Merchant branding, real-time checkout, dashboard analytics.
164-
- **Security & Reliability**: Webhook signatures, rate limiting, audit logs.
165-
- **Infrastructure**: Sentry monitoring, Prometheus metrics, database archival.
165+
- **MPP (Stripe Machine Payments)** — payment channels for high-frequency agent interactions without per-tx fees
166+
- **Agent marketplace** — merchants list paywalled APIs, agents discover and pay autonomously
167+
- **Ethereum support** — same frontend, separate backend service for ERC-20 payments
168+
- **Spending policies** — contract accounts with per-agent USDC limits
166169

167-
## Contributing
170+
---
168171

169-
We are actively seeking contributors! See the [GitHub Issues](https://github.com/emdevelopa/Stellar_Payment_API/issues) to get started. Each issue is tagged with complexity (`complexity:trivial`, `complexity:medium`, `complexity:high`) and category.
172+
## Hackathon Notes
170173

171-
If you are new, look for issues labeled `good first issue`.
174+
- All Stellar interactions use real testnet transactions (not mocked)
175+
- The x402 implementation is custom-built on top of the existing PLUTO infrastructure
176+
- The demo agent is fully autonomous — no human interaction required after `node scripts/demoAgent.js`
177+
- Open source: full source code in this repository
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export async function up(knex) {
2+
await knex.schema.createTableIfNotExists("x402_payments", (t) => {
3+
t.uuid("id").primary().defaultTo(knex.raw("gen_random_uuid()"));
4+
t.text("tx_hash").unique().notNullable();
5+
t.decimal("amount", 18, 7).notNullable();
6+
t.text("recipient").notNullable();
7+
t.text("memo").notNullable();
8+
t.text("access_token_hash").notNullable();
9+
t.timestamp("verified_at", { useTz: true }).notNullable().defaultTo(knex.fn.now());
10+
});
11+
12+
await knex.raw("create index if not exists x402_payments_tx_hash_idx on x402_payments(tx_hash)");
13+
}
14+
15+
export async function down(knex) {
16+
await knex.schema.dropTableIfExists("x402_payments");
17+
}

0 commit comments

Comments
 (0)