Skip to main content

MPP payments

The Machine Payments Protocol (MPP) enables crypto-native, per-request payments on the Tempo blockchain. MPP is an additive payment method alongside Stripe and session-based billing — you choose which to use on each request.

How it works

MPP uses an HTTP 402 challenge/response flow:
  1. You send a request to the gateway.
  2. The server returns 402 Payment Required with a challenge containing the price, token, and recipient.
  3. You sign a Tempo transaction matching the challenge.
  4. You retry the request with the signed transaction as a credential in the Authorization header.
  5. The server verifies the payment on-chain and returns the response with a Payment-Receipt header.

Supported networks

NetworkChain IDRPC URLStatus
Tempo Mainnet4217https://rpc.tempo.xyzActive
Tempo Testnet42431https://rpc.moderato.tempo.xyzActive
Set TEMPO_TESTNET=true in your environment to use the testnet during development.

Plugin pricing

Each plugin has a fixed per-request price in USD, settled in pathUSD on Tempo.
PluginPrice per requestDescription
agent$0.05Agent orchestrator
generate-text$0.01LLM text generation
tts$0.03Text-to-speech synthesis
stt$0.02Speech-to-text transcription

Payment credential

After receiving a 402 challenge, build and sign a credential to send with your retry:

Authorization header format

Authorization: Payment <JSON credential>

Credential structure

{
  "scheme": "Payment",
  "transaction": "0x76...",
  "challengeNonce": "a1b2c3d4e5f6..."
}
FieldTypeDescription
schemestringAlways Payment
transactionstringHex-encoded signed Tempo transaction (prefixed with 0x76 type marker)
challengeNoncestringThe nonce value from the 402 challenge (replay protection)

402 challenge structure

When a payment is required, the server responds with:
{
  "error": "payment_required",
  "message": "Payment required for agent. Choose payment method: Stripe or Tempo MPP.",
  "mpp": {
    "scheme": "Payment",
    "amount": "0.05",
    "currency": "0x20c0000000000000000000000000000000000000",
    "recipient": "0xd8fd0e1dce89beaab924ac68098ddb17613db56f",
    "description": "Agent orchestrator request",
    "nonce": "a1b2c3d4e5f6...",
    "expiresAt": 1742472000000
  },
  "stripe": {
    "checkoutUrl": "/api/v1/payments/stripe/create?plugin=agent",
    "amount": "0.05",
    "currency": "usd"
  }
}

Challenge fields

FieldTypeDescription
schemestringAlways Payment
amountstringPrice in USD
currencystringToken contract address (pathUSD)
recipientstringWallet address to pay
descriptionstringHuman-readable description of the charge
noncestringUnique nonce for this challenge (used for replay protection)
expiresAtnumberUnix timestamp (ms) when the challenge expires. Challenges are valid for 5 minutes.

Verification

The server verifies your credential by checking:
  1. The transaction is hex-encoded and starts with the 0x76 type marker.
  2. The recipient address matches the expected recipient.
  3. The token address matches the expected currency (pathUSD).
  4. The amount matches the plugin price (within a 0.0001 tolerance).
  5. The nonce matches the original challenge nonce.
If verification fails, the server returns an error with a description of the mismatch.

Receipt

On success, the server returns:
  • A Payment-Receipt response header containing the transaction hash.
  • The payment.receipt field in the JSON response body.

Client usage

Use mppFetch to handle the full 402 flow automatically:
import { mppFetch } from '@agentbot/sdk';

const result = await mppFetch({
  plugin: 'agent',
  body: { messages: [{ role: 'user', content: 'Hello' }] },
  privateKey: '0xYOUR_PRIVATE_KEY',
  baseUrl: 'https://agentbot.raveculture.xyz',
  testnet: false,
});

if (result.success) {
  console.log(result.data);
  console.log('Receipt:', result.receipt);
}

mppFetch options

OptionTypeRequiredDefaultDescription
pluginstringYesPlugin ID to call
bodyobjectYesRequest body forwarded to the plugin
privateKeystringYesHex-encoded private key for signing Tempo transactions
baseUrlstringNohttps://agentbot.raveculture.xyzAgentbot instance URL
streambooleanNofalseRequest a streaming response
testnetbooleanNofalseUse Tempo testnet instead of mainnet

mppFetch result

FieldTypeDescription
successbooleanWhether the request succeeded
dataobjectResponse body (non-streaming)
streamReadableStreamResponse stream (streaming)
receiptstringPayment receipt hash
errorstringError message on failure

Check MPP support

You can check whether an endpoint supports MPP payments:
import { checkMppSupport } from '@agentbot/sdk';

const { supported } = await checkMppSupport(
  'https://agentbot.raveculture.xyz/api/v1/gateway'
);
The function sends an OPTIONS request and checks for a WWW-Authenticate: Payment header.

Sessions

Payment sessions provide off-chain, per-call billing without an on-chain transaction for every request. This reduces latency to sub-100ms per call while still settling on-chain periodically.

How sessions work

  1. Open a session — deposit pathUSD (minimum 1.00,maximum1.00, maximum 100.00) into escrow via POST /api/wallet/sessions. You can also fund your session via Stripe using the wallet top-up endpoint.
  2. Make gateway requests — send requests to the gateway with X-Session-Id and X-Wallet-Address headers. The gateway auto-debits your session balance via an off-chain voucher on each call. You can also submit vouchers directly via POST /api/wallet/sessions/voucher.
  3. Automatic settlement — when accumulated vouchers reach $5.00 or after one hour, the server batches them into a single on-chain transaction.
  4. Close the session — call DELETE /api/wallet/sessions?sessionId=ses_... to settle any remaining vouchers and return unused funds.

Session configuration

ParameterValueDescription
Minimum deposit$1.00Minimum amount to open a session
Maximum deposit$100.00Maximum amount per session
Settle threshold$5.00Accumulated voucher total that triggers on-chain settlement
Settle interval1 hourMaximum time between on-chain settlements

Session states

StateDescription
activeSession is open and accepting vouchers
settlingVouchers are being settled on-chain (temporary)
closedSession has been closed and remaining funds returned

When to use sessions vs. per-request MPP

  • Sessions are ideal for high-frequency agent calls where sub-100ms billing latency matters (e.g., chat, real-time orchestration). The gateway auto-debits your session on each call when you provide X-Session-Id and X-Wallet-Address headers.
  • Per-request MPP (the standard 402 flow) is better for infrequent or large-value calls where on-chain settlement per request is acceptable.
See the Wallet API — MPP payment sessions reference for the full endpoint documentation and the Gateway API for how sessions integrate with the gateway.

Troubleshooting

The plugin may not have a configured price. Only plugins listed in the pricing table above support MPP payments.
  • Ensure the challengeNonce matches the nonce from the 402 response.
  • Verify the transaction amount matches the challenge amount exactly.
  • Check that you are using the correct network (mainnet vs. testnet).
The transaction hex must begin with 0x76 (the Tempo transaction type marker). Ensure your signing implementation includes this prefix.