TON blockchain payment method for the Machine Payments Protocol (MPP)
Enable AI agents to pay for services using TON native coins or Jettons. Built for the TON AI Hackathon (March 2026) — Agent Infrastructure Track.
MPP (Machine Payments Protocol) is an open standard by Stripe + Tempo for machine-to-machine payments. When an agent requests a paid resource, the server returns HTTP 402 Payment Required with a challenge. The agent pays and retries — getting access automatically.
mpp-ton adds TON blockchain as a payment rail, so agents can pay with:
- TON coins (native transfers)
- Jettons (USDT, etc.) — coming soon
┌──────────────────────────────────────────────────────────────┐
│ MPP Flow │
│ │
│ ┌─────────┐ GET /api/data ┌─────────────┐ │
│ │ Agent │ ──────────────────────▶│ Server │ │
│ │ (Client) │ ◀───── 402 + Challenge │ (mppx + │ │
│ │ │ │ mpp-ton) │ │
│ │ │ ┌───────────────┐ │ │ │
│ │ │ │ TON Blockchain│ │ │ │
│ │ │──▶ Send Payment │ │ │ │
│ │ │ └───────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ GET /api/data │ │ │
│ │ │ + Payment Credential │ │ │
│ │ │ ──────────────────────▶│ Verify tx │ │
│ │ │ ◀───── 200 + Receipt │ on-chain │ │
│ └─────────┘ + Data └─────────────┘ │
└──────────────────────────────────────────────────────────────┘
npm install @tesserae/mpp-tonimport crypto from 'node:crypto'
import { Mppx } from 'mppx/server'
import { tonCharge } from '@tesserae/mpp-ton/server'
import { tonToNano } from '@tesserae/mpp-ton'
const mppx = Mppx.create({
methods: [
tonCharge({
recipient: 'EQD...your-wallet-address...',
network: 'testnet',
}),
],
secretKey: crypto.randomBytes(32).toString('base64'),
})
// In your request handler:
export async function handler(request: Request) {
const result = await mppx.charge({
amount: tonToNano('0.1'), // 0.1 TON
recipient: 'EQD...your-wallet-address...',
})(request)
if (result.status === 402) return result.challenge
return result.withReceipt(Response.json({ data: 'premium content' }))
}import { Mppx } from 'mppx/client'
import { tonCharge } from '@tesserae/mpp-ton/client'
const mppx = Mppx.create({
methods: [
tonCharge({
mnemonic: ['word1', 'word2', '...', 'word24'],
network: 'testnet',
}),
],
polyfill: false,
})
// Automatically handles 402 → pay → get data
const res = await mppx.fetch('https://api.example.com/weather-data')
const data = await res.json()mpp-ton/
├── packages/
│ └── mpp-ton/ # Core payment method (npm: @tesserae/mpp-ton)
│ └── src/
│ ├── index.ts # Method definition + exports
│ ├── client.ts # Client-side credential creation
│ ├── server.ts # Server-side verification
│ ├── ton-api.ts # TON Center API helpers
│ └── types.ts # Shared types
├── apps/
│ ├── demo-server/ # Weather data API (charges TON)
│ └── demo-client/ # Agent that pays for weather data
├── package.json # Workspace root
└── README.md
import { ton } from '@tesserae/mpp-ton'
// ton.name === 'ton'
// ton.intent === 'charge'Request Parameters (what the server specifies):
| Field | Type | Description |
|---|---|---|
amount |
string |
Amount in nanoTON (1 TON = 1e9) |
recipient |
string |
TON wallet address |
jetton |
string? |
Jetton master address (optional) |
network |
string? |
'mainnet' or 'testnet' |
memo |
string? |
Payment memo/comment |
Credential Payload (what the client sends as proof):
| Field | Type | Description |
|---|---|---|
txHash |
string |
Transaction hash on TON |
boc |
string? |
Signed BOC for pull mode |
lt |
string? |
Logical time |
senderAddress |
string |
Sender wallet address |
tonCharge({
mnemonic: string[] // 24-word mnemonic
// OR
secretKey: string // 64-byte hex secret key
network: 'testnet' // 'mainnet' | 'testnet'
apiKey: string // TON Center API key (optional)
endpoint: string // Custom API endpoint (optional)
})tonCharge({
recipient: string // Your TON wallet address (required)
network: 'testnet' // 'mainnet' | 'testnet'
apiKey: string // TON Center API key (optional)
endpoint: string // Custom API endpoint (optional)
maxTxAge: 300 // Max transaction age in seconds
})import { tonToNano, nanoToTon, TON_DECIMALS, NANOTON_PER_TON } from '@tesserae/mpp-ton'
tonToNano('1.5') // '1500000000'
nanoToTon('100000000000') // '100'git clone https://github.com/tesserae-labs/mpp-ton
cd mpp-ton
npm install
npm run build# Uses a demo wallet address on testnet
npm run demo:serverThe server starts at http://localhost:3000 and charges 0.1 TON per weather data request.
# Generate a new wallet (you'll need to fund it on testnet)
npm run demo:clientOr with an existing wallet:
TON_MNEMONIC="word1 word2 ... word24" npm run demo:client- Run the client once to generate a wallet address
- Open @testgiver_ton_bot on Telegram
- Send your wallet address to get testnet TON
- Run the client again
- Client sends payment to the recipient address on TON
- Client creates credential with
txHash,senderAddress, and optionallt - Server receives credential and queries TON Center API
- Server verifies:
- Transaction exists and is recent (< 5 min by default)
- Recipient matches the expected address
- Amount is >= the required amount
- (For Jettons: correct Jetton master address)
- Server returns Receipt with the verified tx hash
Tesserae GPU Hackathon — March 2026
This project demonstrates how the Machine Payments Protocol can be extended beyond its built-in payment methods (Tempo, Stripe) to support any blockchain. TON is a natural fit because:
- Fast finality (~5 seconds) — agents don't wait long
- Low fees (~$0.01) — viable for micropayments
- 900M+ Telegram users — massive potential user base for agents
- Jetton ecosystem — USDT on TON for stablecoin payments
The architecture follows MPP's custom payment method pattern (Method.from → Method.toClient → Method.toServer), making it a drop-in addition to any MPP-enabled service.
MIT
Built with 🧭 by Tesserae for the Machine Payments Protocol ecosystem.