Machine Payments Protocol (MPP) on Sui — payment method, discovery tooling, and ecosystem hub.
| Package | Version | Description |
|---|---|---|
@suimpp/mpp |
Sui USDC payment method for MPP — client + server | |
@suimpp/discovery |
Discovery validation CLI — OpenAPI checks + 402 probe |
| App | Domain | Description |
|---|---|---|
suimpp.dev |
suimpp.dev | Ecosystem hub — server registry, payment explorer, spec, docs |
npm install @suimpp/mpp mppximport { sui } from '@suimpp/mpp/server';
import { Mppx } from 'mppx';
const mppx = Mppx.create({
methods: [sui({
currency: '0xdba...::usdc::USDC',
recipient: '0xYOUR_ADDRESS',
})],
});
export const GET = mppx.charge({ amount: '0.01' })(
() => Response.json({ data: 'paid content' })
);import { sui } from '@suimpp/mpp/client';
import { Mppx } from 'mppx/client';
const mppx = Mppx.create({
methods: [sui({ client, signer })],
});
const response = await mppx.fetch('https://api.example.com/resource');npx @suimpp/discovery check mpp.t2000.aiThe Machine Payments Protocol is an open standard by Stripe and Tempo Labs for agent-to-service payments. When a server returns HTTP 402 Payment Required, the client pays automatically and retries — no API keys, no subscriptions, no human approval.
@suimpp/mpp implements Sui USDC as a payment method. @suimpp/discovery validates that servers correctly advertise their payment terms via OpenAPI.
Agent Server Sui
│ │ │
│── POST /api/resource ────────────>│ │
│ │ │
│<── 402 Payment Required ─────────│ │
│ WWW-Authenticate: MPP │ │
│ method="sui" amount="0.01" │ │
│ currency="0xdba...::usdc" │ │
│ recipient="0xabc..." │ │
│ │ │
│ ┌─ Build TX: split + transfer USDC ───────────────────────────>│
│ └─ TX confirmed ←──────────────────────────────────────────────│
│ digest: "Hp4oHHs..." │ │
│ │ │
│── Retry + credential {digest} ──>│ │
│ │── getTransaction(digest) ──>│
│ │ verify: success, amount, │
│ │ recipient matches │
│ │ │
│<── 200 OK + response ────────────│ │
│ Payment-Receipt: sui:... │ │
Any server implementing the MPP protocol with Sui USDC can register on suimpp.dev. Registration is validation-gated — no manual approval needed.
Provider enters URL at suimpp.dev/register
│
├── 1. Validate (POST /api/validate)
│ ├── Fetch {url}/openapi.json
│ │ → Parse OpenAPI 3.x document
│ │ → Extract endpoints with x-payment-info
│ │ → Validate schemas, pricing, 402 responses
│ │
│ ├── Probe first POST endpoint
│ │ → Send empty request, expect 402
│ │ → Parse WWW-Authenticate header
│ │ → Verify: method=sui, valid USDC type, valid recipient
│ │
│ └── Return pass/fail checklist
│
├── 2. Preview
│ → Server name, endpoint count, price range
│ → Scrollable endpoint list with pricing
│
└── 3. Register (POST /api/register)
→ Re-validates server-side (never trust client)
→ Creates Server record with slug, categories, endpoints
→ Server appears at /servers/{slug}
What gets validated:
| Check | Source | Required |
|---|---|---|
OpenAPI document at /openapi.json |
@suimpp/discovery fetch |
Yes |
Endpoints with x-payment-info |
OpenAPI parse | Yes (at least 1) |
| 402 challenge on live probe | HTTP request | Yes |
method=sui in WWW-Authenticate |
402 response | Yes |
| Valid USDC coin type | 402 response | Yes |
| Valid Sui recipient address | 402 response | Yes |
| Request/response schemas | OpenAPI parse | Warning only |
Payments are reported by the gateway (application layer), not by the library directly. This ensures every report includes both on-chain data and HTTP request context.
@suimpp/mpp (library) Gateway (application)
───────────────────── ─────────────────────
verify() runs after charge() middleware wraps
on-chain check: the HTTP handler:
┌─────────────────────┐ ┌─────────────────────┐
│ Extract from chain: │ onPayment() │ Extract from HTTP: │
│ • digest │──────────────>│ • service name │
│ • sender address │ (by digest) │ • endpoint path │
│ • amount │ │ • server URL │
│ • recipient │ │ │
│ • currency │ │ Merge on-chain + │
│ • network │ │ request context │
└─────────────────────┘ └──────────┬──────────┘
│
POST /api/report
(all fields in one request)
│
▼
┌─────────────────────┐
│ suimpp.dev/api/report│
│ │
│ Match server by URL │
│ Dedupe by digest │
│ Store payment │
└─────────────────────┘
Why this pattern? The verify() callback has on-chain data (sender from balance changes) but no HTTP context (which endpoint was called). The gateway's charge wrapper has HTTP context but no on-chain data. The onPayment callback bridges the two layers using the digest as the join key.
Implementation:
import { sui } from '@suimpp/mpp/server';
import type { PaymentReport } from '@suimpp/mpp/server';
// 1. Library emits on-chain data via callback
const pendingReports = new Map<string, PaymentReport>();
const mppx = Mppx.create({
methods: [sui({
currency: SUI_USDC_TYPE,
recipient: TREASURY_ADDRESS,
network: 'mainnet',
onPayment: (report) => {
pendingReports.set(report.digest, report);
},
})],
});
// 2. After charge() returns, gateway enriches with request context
const response = await mppx.charge({ amount })(handler)(request);
if (response.status !== 402) {
const digest = parseDigest(response.headers.get('Payment-Receipt'));
const report = digest ? pendingReports.get(digest) : undefined;
if (report) {
pendingReports.delete(digest);
// 3. Single report with all fields
fetch('https://suimpp.dev/api/report', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
...report, // digest, sender, recipient, amount, currency, network
serverUrl: SERVER_URL,
service: 'openai',
endpoint: '/openai/v1/chat/completions',
}),
}).catch(() => {});
}
}@suimpp/discovery validates that a server correctly implements the MPP protocol:
import { check } from '@suimpp/discovery';
const result = await check('https://mpp.example.com');
result.ok // true if no errors (warnings allowed)
result.discovery // OpenAPI parse: title, endpoints, issues
result.probe // 402 probe: status, recipient, currency
result.summary // { totalIssues, errors, warnings }Phase 1 — OpenAPI Discovery:
- Fetches
{origin}/openapi.json - Validates OpenAPI 3.x structure
- Extracts endpoints with
x-payment-infoextensions - Reports: missing schemas, invalid pricing, missing 402 responses
Phase 2 — Endpoint Probe:
- Sends an empty POST to the first payable endpoint
- Expects HTTP 402 with
WWW-Authenticateheader - Validates:
method=sui, USDC coin type, valid Sui recipient address
# CLI usage
npx @suimpp/discovery check mpp.t2000.ai
# Output:
# ✓ OpenAPI document found at /openapi.json
# ✓ 88 payable endpoints detected
# ✓ 402 challenge response verified
# ✓ Sui USDC payment method detected
# ✓ Recipient: 0x76d7...5012
# 0 errors, 0 warningspnpm install
pnpm build
pnpm test
pnpm typecheck# Bump versions in package.json files
git add -A && git commit -m "📦 build: bump versions"
git tag v0.4.0
git push && git push --tags
# CI: build → typecheck → test → publish to npm → GitHub ReleaseMIT