MPP - Protocolo de Pagamentos entre Máquinas
O MPP é um protocolo aberto (coautorado pela Tempo e Stripe) que padroniza o HTTP 402 Payment Required para pagamentos entre máquinas. Clientes pagam na mesma requisição HTTP - sem contas, chaves de API ou fluxos de checkout.
A especificação central do protocolo foi submetida à IETF como Payment HTTP Authentication Scheme.
O código neste skill usa nomes de token placeholder (<USDC_TEMPO_MAINNET>, <PATHUSD_TESTNET>); os endereços reais estão na documentação da Tempo e em references/tempo-method.md.
Arquitetura Central
Três primitivas alimentam cada pagamento MPP:
- Challenge - requisição de pagamento emitida pelo servidor (no cabeçalho
WWW-Authenticate: Payment) - Credential - prova de pagamento submetida pelo cliente (no cabeçalho
Authorization: Payment) - Receipt - confirmação do servidor de pagamento bem-sucedido (no cabeçalho
Payment-Receipt)
Métodos e Intenções de Pagamento
O MPP é agnóstico ao método de pagamento. Cada método define seu próprio trilho de liquidação:
| Método | Trilho | Pacote SDK | Status |
|---|---|---|---|
| Tempo | Stablecoins TIP-20 na cadeia Tempo | mppx (integrado) | Produção |
| Stripe | Cartões/carteiras (SPT) + depósito cripto on-chain | mppx (integrado) | Produção |
| EVM | Autorizações de stablecoin EIP-3009 (compatível com x402-exact) | mppx (integrado) | Produção |
| Lightning | Bitcoin via Rede Lightning | @buildonspark/lightning-mpp-sdk | Produção |
| Stellar | Tokens SEP-41 na Stellar, charge + channel | @stellar/mpp | Produção (especificação channel ainda em rascunho - sujeita a alterações) |
| Solana | Charge + sessão nativa da Solana (SOL, SPL, Token-2022) | @solana/mpp | Produção |
| Monad | Charge Monad (ERC-3009, modos de liquidação) | @monad-crypto/mpp | Produção |
| NEAR Intents | Charge cross-chain via endereços de depósito 1Click | @defuse-protocol/nearintents-mpp-sdk | Produção (não é trustless - roteia por um backend de liquidação, anunciado como methodDetails.settlementBackend: "near-intents" para política de risco por método) |
| RedotPay | Saldo RedotPay (rdt) ou prova de stablecoin, apenas charge | @redotpay/mpp | Produção |
| Card | Tokens de rede criptografados (Visa) | mpp-card | Produção |
| Customizado | Qualquer trilho | Method.from() + Method.toClient/toServer | Extensível |
Aprofundamentos por método: references/tempo-method.md, references/stripe-method.md, references/lightning-method.md, references/custom-methods.md.
| Intenção | Padrão | Melhor Para |
|---|---|---|
| charge | Pagamento único por requisição | Chamadas de API, acesso a conteúdo, endpoints de preço fixo |
| session | Pague conforme o uso via canais de pagamento | Streaming LLM, faturamento medido, APIs de alta frequência |
| subscription | Acesso recorrente via uma chave autorizada (Tempo) - veja references/subscriptions.md | Planos/tiers onde o acesso é separado da cobrança por requisição |
Início Rápido: Servidor (TypeScript)
import { Mppx, tempo } from 'mppx/server'
const mppx = Mppx.create({
methods: [tempo({
currency: '<PATHUSD_TESTNET>', // pathUSD testnet
recipient: '0xYourAddress',
})],
})
export async function handler(request: Request) {
const result = await mppx.charge({ amount: '0.01' })(request)
if (result.status === 402) return result.challenge
return result.withReceipt(Response.json({ data: '...' }))
}
Instalação: npm install mppx viem (mppx 0.8.15 requer viem >= 2.54.0).
Valide o servidor finalizado de ponta a ponta com npx mppx validate http://localhost:3000.
Início Rápido: Cliente (TypeScript)
import { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'
// Polyfills globalThis.fetch para lidar com 402 automaticamente
Mppx.create({
methods: [tempo({ account: privateKeyToAccount('0x...') })],
})
const res = await fetch('https://api.example.com/paid')
// O pagamento ocorre de forma transparente quando o servidor retorna 402
Em navegadores, o mppx 0.6.0 mudou o padrão: o fetch polyfillado só envia Accept-Payment para endpoints de mesma origem, então APIs pagas com origem cruzada precisam de acceptPaymentPolicy ('always' / { origins: [...] }). O cliente tenta novamente desafios incrementais até maxPaymentRetries (padrão 3). Para alternativas não globais (Fetch.from/polyfill/restore, Mppx.restore()), veja references/typescript-sdk.md.
Início Rápido: Servidor (Python)
from fastapi import FastAPI
from mpp import Credential, Receipt
from mpp.server import Mpp
from mpp.methods.tempo import tempo, ChargeIntent
app = FastAPI()
server = Mpp.create(method=tempo(
currency="<PATHUSD_TESTNET>",
recipient="0xYourAddress", intents={"charge": ChargeIntent()},
))
@app.get("/resource")
@server.pay(amount="0.50")
async def get_resource(request, credential: Credential, receipt: Receipt):
return {"data": "paid content", "payer": credential.source}
Instalação: pip install "pympp[tempo]". Veja references/python-sdk.md para padrões completos.
Início Rápido: Servidor (Rust)
Instalação: cargo add mpp --features tempo,server. Veja references/rust-sdk.md para padrões completos.
Middleware de Frameworks (TypeScript)
Cada framework tem sua própria importação (mppx/nextjs, mppx/hono, mppx/express, mppx/elysia):
// Next.js
import { Mppx, tempo } from 'mppx/nextjs'
const mppx = Mppx.create({ methods: [tempo({ currency: '<PATHUSD_TESTNET>', recipient: '0x...' })] })
export const GET = mppx.charge({ amount: '0.1' })(() => Response.json({ data: '...' }))
// Hono
import { Mppx, tempo } from 'mppx/hono'
app.get('/resource', mppx.charge({ amount: '0.1' }), (c) => c.json({ data: '...' }))
Veja references/typescript-sdk.md para exemplos com Express e Elysia.
Sessões: Streaming Pague Conforme o Uso
Sessões abrem um canal de pagamento uma vez e depois usam vouchers fora da cadeia para cada requisição - nenhuma transação blockchain por requisição. Latência abaixo de 100ms, taxas quase zero por requisição.
Sessões v2 (padrão desde mppx 0.7.0): tempo.session() é o fluxo de canal precompile TIP-1034; a implementação anterior de contrato de custódia é Sessões v1, ainda disponível como o obsoleto tempo.sessionLegacy. Um cliente que espera v2 rejeita uma sessão v1 e cai no caminho charge, então mantenha cliente e servidor em fluxos correspondentes. Duas APIs de cliente: tempo.session({ account, maxDeposit }) registra o método com Mppx.create() (tratamento transparente de 402 via fetch), enquanto tempo.session.manager({ account, maxDeposit }) retorna um cliente gerenciado para controle direto do ciclo de vida (.sse(), .close()).
// Servidor - endpoint de sessão com liquidação automática
const mppx = Mppx.create({
methods: [tempo.session({
currency: '<PATHUSD_TESTNET>', recipient: '0x...',
store: Store.redis(redis),
settlementSchedule: { amount: '1.00', intervalMs: 300_000 },
bootstrap: true, // permite que clientes recorrentes recuperem seu canal nesta rota
})],
})
const result = await mppx.session({ amount: '0.001', unitType: 'token' })(request)
if (result.status === 402) return result.challenge
return result.withReceipt(Response.json({ data: '...' }))
// Servidor - streaming SSE com cobrança por palavra
export const GET = mppx.session({ amount: '0.001', unitType: 'word' })(
async () => async function* (stream) {
for (const word of ['hello', 'world']) {
await stream.charge()
yield word
}
}
)
// Cliente - sessão com canal gerenciado automaticamente
Mppx.create({ methods: [tempo({ account, maxDeposit: '1' })] })
const res = await fetch('http://localhost:3000/api/resource')
// 1ª requisição: abre canal on-chain; 2+ requisições: vouchers off-chain
Sessões também transmitem via WebSocket usando Ws.serve(). Veja references/sessions.md para o ciclo de vida completo, liquidação, armazenamentos, padrões SSE e WebSocket, e recuperação de canal.
Suporte a Múltiplos Métodos
Aceite stablecoins Tempo, cartões Stripe e Bitcoin Lightning em um único endpoint:
const mppx = Mppx.create({
methods: [
tempo({ currency: '<PATHUSD_TESTNET>', recipient: '0x...' }),
stripe.charge({ client: new Stripe(key), networkId: 'profile_...', paymentMethodTypes: ['card'] }),
spark.charge({ mnemonic: process.env.MNEMONIC! }),
],
})
Use Mppx.compose() para apresentar múltiplos métodos em uma única resposta 402 com preços por rota. Aplique a mesma ramificação no site do desafio e no site de verificação, ou o 402 anuncia menos opções do que o servidor aceita. Veja references/typescript-sdk.md.
Links de Pagamento (HTML)
Definir html: true na configuração de um método de pagamento renderiza uma página de pagamento amigável ao navegador quando um endpoint 402 é visitado em um navegador, com temas, abas de composição multi-método e suporte a carteira Solana. Service workers cuidam do envio da credencial, então a página recarrega com a resposta paga.
Personalize via exportações de mppx/html (Config, Text, Theme), e construa o link de pagamento de um método personalizado com Html.init(methodName).
Autenticação de Custo Zero (Credenciais de Prova)
Autentique a identidade do agente sem pagamento. Clientes assinam uma prova EIP-712 sobre o ID do desafio em vez de criar uma transação - sem gastar gás, sem transferir fundos.
// Servidor - charge de custo zero, com armazenamento para proteção contra repetição
const mppx = Mppx.create({
methods: [tempo.charge({ currency: '<PATHUSD_TESTNET>', recipient: '0x...', store })],
})
const result = await mppx.charge({ amount: '0' })(request)
Desde mppx 0.8.0, essas provas são vinculadas à carteira do pagador: os dados tipados EIP-712 Proof (expostos como tempo.Proof) carregam um campo account na versão de domínio 3, então uma prova assinada para uma conta não é mais verificada contra outra.
Casos de uso: verificação de identidade, polling de trabalhos de longa duração, desbloqueio pago com acesso gratuito subsequente, pipelines de agentes em várias etapas. Veja mpp.dev/advanced/identity.
Proxy de Pagamentos
Proteja APIs existentes com pagamentos MPP:
// import { openai, Proxy } from 'mppx/proxy' - um serviço dentro de Proxy.create({ services: [...] })
openai({
apiKey: process.env.OPENAI_API_KEY,
routes: {
'POST /v1/chat/completions': mppx.charge({ amount: '0.05' }),
'GET /v1/models': true, // literal `true` marca uma rota gratuita
},
})
Presets integrados openai(), anthropic(), stripe(), além de custom() para qualquer upstream. Veja references/discovery-and-proxy.md para Proxy.create(), os endpoints de descoberta que ele serve, e o auxiliar discovery() para servidores não proxy.
Transporte MCP
Chamadas de ferramentas MCP podem exigir pagamento usando o código de erro JSON-RPC -32042 (servidores também podem emitir -32043):
// Servidor - importe tempo de mppx/server, NÃO de mppx/tempo
import { McpServer } from 'mppx/mcp/server'
import { tempo } from 'mppx/server'
const server = McpServer.wrap(baseServer, { methods: [tempo.charge({ /* ... */ })], secretKey })
// Cliente - cliente MCP ciente de pagamento (importe tempo de mppx/client)
import { McpClient } from 'mppx/mcp/client'
import { tempo } from 'mppx/client'
const mcp = McpClient.wrap(client, { methods: [tempo({ account })] })
const result = await mcp.callTool({ name: 'premium_tool', arguments: {} })
Desafios MCP-over-HTTP são liquidados no mesmo fetch ciente de pagamento, e os transportes são plugáveis via Transport.from/http/mcp/mcpSdk em ambos os lados. Veja references/transports.md.
Carteiras de Servidor Privy
createViemAccount de @privy-io/node/viem (requer @privy-io/node >= 0.20.0) retorna uma Account viem apoiada por uma carteira de servidor Privy, então ela se encaixa em tempo({ account }) onde quer que uma conta local iria.
A assinatura no lado do servidor funciona com carteiras de servidor de propriedade do app; carteiras incorporadas de propriedade do usuário exigem chaves de autorização ou quóruns de chaves. Veja references/typescript-sdk.md para a configuração completa e a construção manual toAccount().
Testes e CLI
# Cria uma conta (armazenada no keychain), depois a financia na testnet
npx mppx account create
npx mppx account fund --network testnet
# Faz uma requisição paga
npx mppx http://localhost:3000/resource
# Analisa um desafio sem assiná-lo
npx mppx sign --dry-run --challenge '<www-authenticate value>'
# Valida uma implementação de servidor de ponta a ponta
npx mppx validate http://localhost:3000
O CLI também cobre init, sessions (listar/visualizar/fechar), discover, services, mcp add e skills add. A configuração vem de MPPX_CONFIG ou um --config explícito - não há descoberta automática a partir do diretório de trabalho. Referência completa: references/cli.md.
Pacotes SDK
| Linguagem | Pacote | Instalação |
|---|---|---|
| TypeScript | mppx | npm install mppx |
| Python | pympp | pip install "pympp[tempo]" |
| Rust | mpp | cargo add mpp --features tempo,client,server |
| Ruby | mpp-rb (oficial, pela Stripe) | veja repositório para nome da gem |
| Go | mpp-go (oficial, pela Tempo) | go get github.com/tempoxyz/mpp-go |
| Elixir | mpp (comunitário) | hex.pm/packages/mpp |
| Swift | mpp-swift (comunitário) | veja repositório |
Notas de capacidade, verificadas contra a fonte do SDK em vez das matrizes de documentação (upstream publica duas que discordam):
- Intenção Session: apenas TypeScript e Rust.
- Credenciais de Prova (autenticação de custo zero): TypeScript