PayGate is a pay-per-call gateway for APIs on Stellar testnet.
It lets a developer register a normal API, expose it through a PayGate paid proxy, let AI agents or machine clients pay per request through Stellar MPP, and track revenue, fees, calls, and withdrawals from a developer dashboard.
PayGate V1 is a testnet beta candidate. It is designed to prove the product loop, not to handle mainnet funds yet.
Detailed Docs · Developer Guide · V1 Product Spec · Demo Guide · Beta Readiness · OpenSpec
- What Is PayGate?
- Why This Matters
- Current Status
- Review Path
- Core Flow
- Architecture
- Features
- API Surface
- Local Development
- Environment Variables
- Supabase Setup
- Deployment
- Verification Checklist
- Demo Evidence
- Project Structure
- V1 Boundaries
- Roadmap
- References
PayGate is a gateway layer for developers who want to monetize API calls without building payment infrastructure from scratch.
Instead of asking API buyers to subscribe, create accounts, or go through human-style checkout, PayGate exposes a paid proxy endpoint:
AI agent / machine client
-> PayGate paid proxy
-> original developer API
The developer keeps their API normal. PayGate handles:
- Freighter wallet login for developer identity.
- API registration and paid proxy generation.
- HTTP
402 Payment Requiredchallenges. - Stellar MPP payment verification.
- Soroban escrow crediting.
- 90% developer / 10% PayGate fee split.
- Dashboard reporting.
- Developer withdrawal.
The original SOW/V0 code generator still exists at /generate, but it is now treated as a legacy helper. The main V1 product flow starts at /dashboard and /apis/new.
Developers integrating their own API should start with the Developer Guide. It explains the PayGate proxy URL, API secret, upstream guard, and 401/402/200 testing flow.
Most API monetization assumes a human buyer:
- create an account,
- enter a card,
- choose a plan,
- manage subscription billing,
- then call the API.
That flow is awkward for AI agents and machine clients. Agents need something more direct:
- request a resource,
- receive a payment challenge,
- pay for that single call,
- retry with proof,
- receive the API response.
PayGate demonstrates that pattern with Stellar testnet USDC, MPP, and a PayGate-controlled paid gateway.
PayGate V1 currently supports the full testnet beta loop locally and in deploy-ready code:
| Area | Status |
|---|---|
| Freighter wallet login | Done |
| Supabase-backed auth challenges | Done |
| API registry | Done |
| API lifecycle: pending setup -> active -> archived | Done |
| Upstream ownership verification | Done |
| Duplicate live endpoint prevention | Done |
| API delete/archive for demo reset | Done |
| API secret encryption | Done |
Paid proxy /api/pay/:apiId |
Done |
MPP unpaid 402 flow |
Done |
MPP paid 200 flow |
Done, testnet proof captured |
| Soroban escrow contract | Done for testnet demo |
| 90% developer / 10% PayGate split | Done |
| Dashboard summary | Done |
| Developer withdrawal | Done |
| Platform fee withdrawal command | Done |
| Beta evidence package | Done |
| Production live replay | Pending |
| Demo video | Pending |
Read the current readiness note in docs/evidence/PAYGATE_V1_BETA_READINESS.md.
For a reviewer or demo session, the shortest path is:
- Open the deployed PayGate app.
- Connect Freighter on Stellar Testnet.
- Open
/apis/newand register the demo upstream API. - Copy the generated proxy URL and API secret.
- Set
PAYGATE_DEMO_UPSTREAM_SECRETto the generated secret. - Redeploy the upstream so the secret guard is live.
- Open the API detail page and click
Verify setup; the API should move fromPending setuptoActive. - Call the original upstream without the secret and confirm
401. - Call the PayGate proxy without payment and confirm
402. - Run the local agent/client to pay with testnet USDC.
- Confirm the proxy returns
200with the upstream JSON response. - Open
/dashboardand verify calls, payment tx, credit tx, revenue, fee, and withdrawable balance. - Withdraw developer balance with Freighter.
The detailed replay script lives in docs/PAYGATE_V1_DEMO_GUIDE.md.
sequenceDiagram
participant Dev as Developer
participant PayGate
participant Agent as AI Agent / Client
participant MPP as Stellar MPP
participant Escrow as Soroban Escrow
participant API as Original API
Dev->>PayGate: Connect Freighter and sign login challenge
Dev->>PayGate: Register API URL, path, and USDC price
PayGate-->>Dev: Return paid proxy URL, API secret, and Pending setup state
Dev->>API: Add X-PayGate-Secret guard
Dev->>PayGate: Verify setup
PayGate->>API: Probe upstream with X-PayGate-Secret
PayGate-->>Dev: Mark API Active
Agent->>PayGate: GET /api/pay/:apiId
PayGate-->>Agent: 402 Payment Required
Agent->>MPP: Pay USDC testnet
Agent->>PayGate: Retry request with payment credential
PayGate->>MPP: Verify payment
PayGate->>Escrow: credit_payment(paymentId, developer, amount)
PayGate->>API: Forward request with X-PayGate-Secret
API-->>PayGate: Protected JSON response
PayGate-->>Agent: 200 OK + response
Dev->>PayGate: Open dashboard and withdraw balance
flowchart LR
Frontend["React SPA"] --> Auth["Wallet Auth Functions"]
Frontend --> Registry["API Registry Functions"]
Frontend --> Dashboard["Dashboard Functions"]
Agent["AI Agent / Machine Client"] --> Proxy["PayGate Paid Proxy"]
Proxy --> MPP["Stellar MPP Charge"]
Proxy --> Store["Supabase Postgres"]
Proxy --> Escrow["Soroban Escrow Contract"]
Proxy --> Upstream["Original Developer API"]
Auth --> Store
Registry --> Store
Dashboard --> Store
Dashboard --> Escrow
- Frontend: React 18, Vite, React Router, Tailwind CSS, lucide-react.
- API runtime: Vercel Functions in
api/. - Legacy generator backend: Express in
backend/. - Database: Supabase Postgres.
- Payments:
@stellar/mpp,mppx, Stellar testnet USDC. - Settlement: Soroban escrow contract.
- Wallet: Freighter.
- Demo client: Node.js script in
examples/express-paid-api.
- Connect Freighter wallet.
- Sign a challenge to prove wallet ownership.
- Register a GET JSON API.
- Set price per call in USDC.
- Receive a PayGate paid proxy URL while the API starts in
Pending setup. - Receive a unique
X-PayGate-Secretfor upstream protection. - Verify setup before the API becomes
Active. - Delete unused APIs or archive paid APIs for demo reset without losing history.
- See API calls, successful calls, failed calls, and payment history.
- See gross revenue, developer revenue, and PayGate fee.
- Withdraw escrow balance with a Freighter-signed transaction.
- Call a paid proxy endpoint.
- Receive HTTP
402 Payment Requiredwhen unpaid. - Pay Stellar testnet USDC through MPP.
- Retry the request with payment proof.
- Receive the upstream API response after settlement.
- Verify MPP payment credentials.
- Credit the Soroban escrow ledger.
- Track request and payment state in Supabase.
- Withdraw accumulated platform fees.
- Generate evidence for grant/demo review.
| Method | Path | Description |
|---|---|---|
POST |
/api/generate |
Legacy V0 middleware generator |
GET |
/api/auth/me |
Reads the current wallet session |
POST |
/api/auth/challenge |
Creates a Freighter sign-message challenge |
POST |
/api/auth/verify |
Verifies the signed challenge and creates a session |
POST |
/api/auth/logout |
Clears the wallet session |
GET |
/api/apis |
Lists APIs owned by the connected wallet |
POST |
/api/apis |
Registers a new API |
GET |
/api/apis/:apiId |
Reads one registered API |
PATCH |
/api/apis/:apiId |
Updates API metadata such as name |
DELETE |
/api/apis/:apiId |
Deletes unused APIs or archives APIs with activity |
POST |
/api/apis/:apiId/verify |
Verifies upstream X-PayGate-Secret setup and activates the API |
GET |
/api/pay/:apiId |
Paid proxy endpoint |
GET |
/api/dashboard/summary |
Dashboard summary for the connected wallet |
POST |
/api/withdraw/prepare |
Prepares a Freighter-signed withdrawal transaction |
POST |
/api/withdraw/submit |
Submits a signed withdrawal transaction |
GET |
/api/upstream/market-signal |
Secret-protected demo upstream API |
GET |
/api/demo/market-signal |
Legacy standalone paid sample API |
POST /api/apis
Content-Type: application/json
Cookie: paygate_session=...{
"name": "PayGate Demo Market Signal",
"upstreamBaseUrl": "https://your-paygate-domain.vercel.app",
"path": "/api/upstream/market-signal",
"priceUsdc": 0.01
}Example response:
{
"api": {
"id": "api_id",
"name": "PayGate Demo Market Signal",
"status": "pending_setup",
"active": false,
"proxyUrl": "https://your-paygate-domain.vercel.app/api/pay/api_id",
"secret": "pgsec_...",
"setup": {
"requiredHeader": "X-PayGate-Secret"
}
}
}GET /api/pay/:apiIdWithout payment, PayGate returns HTTP 402 Payment Required. A compatible MPP client pays, retries with the payment credential, and receives the upstream JSON response.
Use Node.js 22+ locally.
npm install
npm --prefix frontend install
vercel env pull .env.local --environment=development --yes
vercel devOpen:
http://localhost:3000
Verify that V1 API functions are loaded:
curl -i http://localhost:3000/api/auth/meExpected before login:
{"authenticated":false}If this request logs a Vite proxy ECONNREFUSED, your linked Vercel project is still using frontend as the Root Directory. Change the Vercel project Root Directory to the repo root.
Use this only for visual checks. It does not load V1 API functions.
cd frontend
npm install
npm run devOpen:
http://localhost:5173
Copy the template:
cp .env.example .env.localRequired server env for V1:
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
SESSION_SECRET=
API_SECRET_ENCRYPTION_KEY=
MPP_SECRET_KEY=
CRON_SECRET=
ESCROW_CONTRACT_ID=
PAYGATE_OPERATOR_SECRET=
PAYGATE_DEMO_UPSTREAM_SECRET=
STELLAR_NETWORK=stellar:testnet
STELLAR_RPC_URL=https://soroban-testnet.stellar.orgGenerate strong random secrets:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Important rules:
- Do not commit
.env.local. - Do not put payer wallet secrets in Vercel.
STELLAR_SECRETbelongs only in the local agent/client environment.- Do not use
PAYGATE_AUTH_CHALLENGE_STORE=memoryorPAYGATE_REGISTRY_STORE=memoryin Vercel. - Set
CRON_SECRETto a random value of at least 16 characters in Vercel Production.
Run these migrations in the Supabase SQL Editor:
supabase/migrations/20260604000000_paygate_v1_registry.sql
supabase/migrations/20260604000001_paygate_v1_paid_proxy.sql
They create the V1 storage layer:
developers
auth_challenges
apis
proxy_requests
payments
withdrawals
mpp_store
Use the Supabase service role key only on the server side.
Supabase Free Plan projects may be paused after sustained low activity. PayGate uses a secured daily Vercel cron request to perform three read-only health queries. This reduces pause risk for the testnet beta, but a paid Supabase plan is still required when uninterrupted production availability becomes a requirement.
PayGate is intended to run as a single Vercel project from the repo root.
Vercel project settings:
Root Directory: repo root
Build Command: npm run build
Output Directory: frontend/dist
Install Command: npm install
Node.js Version: 22.x or 24.x
Check the linked project:
vercel project inspect paygate-stellarThe output must not show:
Root Directory: frontend
If it does, /api/* will fall through to the Vite frontend proxy instead of loading Vercel Functions.
After setting env vars in Vercel:
vercel env pull .env.local --environment=development --yesThe Hobby-compatible cron schedule is defined in vercel.json and calls
/api/cron/database-health once per day. Vercel sends CRON_SECRET as a Bearer
token; requests without the matching token are rejected.
Run from the repo root:
npm run test:beta
npm run audit:prod
npm run test:browser
npm run test:database-health
git diff --checkOptional deployed readiness checks:
npm run beta:preflight
npm run test:auth:supabaseQuick API checks:
curl -i http://localhost:3000/api/auth/me
curl -i http://localhost:3000/api/upstream/market-signal
curl -i http://localhost:3000/api/pay/<apiId>Expected behavior:
/api/auth/mereturns{"authenticated":false}before login./api/upstream/market-signalreturns401withoutX-PayGate-Secret./api/pay/<apiId>returns402without payment.- A paid agent/client retry returns
200with the protected JSON response.
Existing testnet evidence is tracked under docs/evidence/.
| Evidence | File |
|---|---|
| Escrow deploy/init/withdraw/platform fee | Phase 1 settlement proof |
| Wallet auth | Phase 2 wallet auth proof |
| API registry | Phase 3 registry proof |
| Upstream API protection | Phase 4 upstream proof |
Unpaid proxy 402 |
Phase 5 unpaid proxy proof |
Paid proxy 200 and escrow credit |
Phase 6 paid proxy proof |
| Dashboard | Phase 7 dashboard proof |
| Withdrawal | Phase 8 withdrawal proof |
Important testnet tx hashes already captured:
| Action | Tx hash |
|---|---|
| Agent pays escrow through MPP | c7cc23efa9130c1178343d22bd98a0fd5f6e23fde2a2224715a0a7a99b3734a6 |
| PayGate credits escrow ledger | db5e1e1c6d9e6b9d24887ac96cb18a227fd7866d044da6d0db8ccc45c8708ee1 |
| Developer withdraw proof | 8f0647f5595020a394df833b1545e2d4c0e192af960db2b1e3c68dfd679d50d7 |
| Platform fee withdraw proof | 0bf30b3fd0b5385f933dd9b22de39a6c8167e2c6405ac075a2bd13466a26d04b |
Create a new replay folder:
npm run evidence:initpaygate/
├── api/ # Vercel Functions for V1 auth, registry, proxy, dashboard, withdrawal
├── backend/ # Legacy Express generator backend
├── contracts/ # Soroban escrow contract
├── docs/ # Specs, demo guide, handoff docs, evidence
├── examples/express-paid-api # Demo API and local agent/client
├── frontend/ # React SPA
├── openspec/ # OpenSpec changes and capability specs
├── scripts/ # Smoke tests, beta preflight, evidence tooling
├── supabase/ # SQL migrations
├── package.json
└── vercel.json
- Testnet only.
- USDC only.
- GET JSON APIs only.
- Buyer is represented by a local script/agent client.
- No buyer account system yet.
- No prepaid balance yet.
- No refund flow if upstream fails after payment.
- No mainnet, fiat checkout, compliance workflow, or production incident response yet.
- Complete deployed Vercel replay with real env and screenshots.
- Record a concise demo video.
- Add POST/body forwarding.
- Add refund or pending-credit handling for upstream failure.
- Add buyer-side UX or agent SDK.
- Add mainnet readiness review.
- Add provider onboarding polish and API secret rotation.
- Add analytics, webhooks, and richer dashboard filters.
- Stellar MPP documentation
- Stellar MPP Charge guide
- Freighter web app API
- Vercel environment variables
- Supabase documentation
MIT © 2026 PayGate