Skip to main content
The Machine Payments Protocol (MPP) supports session-based micropayments on Tempo. Your agent opens a session with a deposit, makes many requests against it, and the session settles when it closes. Conto checks both MPP charges and sessions against your policies before the agent pays.
MPP endpoints enforce explicit API-key scopes. Pre-authorization requires payments:request, recording settlement requires payments:execute, and budget or service analytics require analytics:read.

Prerequisites

An active agent with an SDK key (Quickstart)
A funded Tempo wallet with pathUSD on testnet or USDC.e on mainnet
An MPP-enabled service to call (or an MPP test service)

MPP vs x402

Use x402 when each API call is independent. Use MPP when your agent will make many requests to the same service in a session, such as streaming data, iterative processing, or chat APIs.

How MPP works

Step 1: Set up MPP policies

Send "intent": "charge" or "intent": "session" on every MPP pre-authorization. Session rules such as MPP_MAX_SESSION_DEPOSIT deny a request with no intent. They also apply to every payment the agent makes, so assign this policy only to an agent that pays for MPP services. The policy rule reference lists every MPP rule type and value format. The two rules below belong to different MPP policy types, so this example uses COMPOSITE.
1

Create the policy

Go to Policies > Create Policy.
2

Add rules

Rule 1: Cap the session depositNo session deposit or one-time charge can exceed $25.Rule 2: Budget per serviceSpend with any one MPP service cannot exceed $50 in a rolling 24 hours.
3

Assign to agent

Go to that agent’s Permissions tab and assign the policy.

Step 2: Pre-authorize the session

Before your agent opens an MPP session, check it with POST /api/sdk/mpp/pre-authorize. Send the deposit amount and "intent": "session". Conto evaluates your MPP policies plus your general spend limits. If pre-authorization returns 503 PAYMENTS_PAUSED, do not open the session: no grant or spend reservation was created. Ask the owner to check payment availability, then retry after service resumes. See error handling for the distinct mainnet payment controls. An approved session returns a grantId and grantSignature and reserves the amount against your spend limits. The grant is a ceiling that your records draw down until grantExpiresAt: the shortest MPP_MAX_SESSION_DURATION that applies, or 24 hours. A record after that is flagged as a policy bypass. Proceed with the wallet already configured for your MPP client. A declined session returns reasons and reasonCodes. SPENDING_LIMIT means a price, deposit, session budget, or rate limit applied, so request a smaller session. See Pre-authorization.

Step 3: Run the session

Open the session with your MPP client, make requests against the deposit, then close it. The service settles the charged total onchain and returns the rest of the deposit.

Step 4: Record in Conto

Record the amount the service charged with POST /api/sdk/mpp/record. Send a stable credentialId, "intent": "session", the same sessionId, and the grantId and grantSignature from Step 2. Record before grantExpiresAt, and send closeSession: true on the final record so Conto closes the session and releases the unused reservation (@conto_finance/sdk 0.5.3 or later). If the service charged nothing, still send the final record with amount: 0, closeSession: true, and the grant. Leave out txHash, because a session record with txHash returns 422. See Recording transactions.
Record the amount the service charged, not the deposit. Recording the deposit overcounts spend against your limits.

Step 5: Monitor spending

Open Machine Spend in the dashboard for spend per service and endpoint. See Machine spend analytics for combined x402 and MPP service spend. From the API, use Budget tracking and Querying services.

Full integration example

This example uses conto.mpp from @conto_finance/sdk. mppClient stands for your MPP client library.

Troubleshooting

If you added MPP_MAX_CONCURRENT_SESSIONS, the agent gets PAYMENT_CONTROLS once it reaches the limit. Conto counts a session as open from its approved pre-authorize until a record sends closeSession: true, or until its MPP_MAX_SESSION_DURATION (24 hours without one) passes. Another pre-authorize for a sessionId that is already open does not count as a new session. Close sessions on the final record, even when nothing was charged, or raise MPP_MAX_CONCURRENT_SESSIONS.
The deposit is locked onchain when the session opens. If your wallet has 15andyoutrytoopena15 and you try to open a 20 session, it fails. Check your wallet balance and request a smaller deposit.
The service determines final settlement. If charges seem wrong, check the session details with the service provider. Record the total the service reports when the session closes. Conto rejects a record whose recipient or currency differs from the grant, or whose amount is more than what is left of it.
No. Conto supports MPP only on Tempo (see Supported chain for chain IDs, currencies, and explorers). For paid APIs on Base or Ethereum, use the x402 protocol instead.

API reference

Pre-authorization

Check a session or a one-time charge before the agent pays. With the SDK, call conto.mpp.preAuthorize() with the same fields.
Conto derives serviceDomain from resourceUrl, so you do not need to send it. Always send intent (charge or session). Session-lifecycle rules deny a pre-authorization without it. Send the scheme, credential, challenge, payment method, and stable session ID when available so MPP service, method, and session-lifecycle controls have the context they require. sessionId is required when intent is session. Response (Approved):
An approved decision issues a grant and reserves amount against the wallet’s spend limits until grantExpiresAt. A charge grant covers one payment of exactly that amount and expires after 10 minutes. A session grant is a ceiling: several records for the same sessionId may draw it down until the total reaches amount or the grant expires. It lasts for the session’s maximum duration: the shortest MPP_MAX_SESSION_DURATION that applies, or 24 hours by default. A record after grantExpiresAt is a policy bypass. When a grant expires, Conto releases the part of the reservation that was not recorded. Retrying pre-authorization with the same challengeId (or credentialId) returns the same live grant. Response (Denied):
A declined or review-required decision includes reasons and reasonCodes. Conto does not queue a review_required payment for a person, so handle it like a decline. The codes name the kind of control without rule values or policy names. SPENDING_LIMIT covers price ceilings, per-endpoint and per-service limits, session budgets and deposits, velocity, and period limits. RECIPIENT_NOT_ALLOWED covers blocked or unlisted services. Concurrent-session, session-duration, session-intent and payment-method rules return PAYMENT_CONTROLS. See payment reasons for the full list.

Recording transactions

After the service charges the agent, record the charged amount. With the SDK, call conto.mpp.record().
When paymentReceipt is supplied, Conto rejects unsuccessful or challenge-mismatched receipts with 400 and amount mismatches with 409. Because the receipt is caller supplied, passing its structural and consistency checks does not confirm settlement. A record without txHash stays PENDING. When txHash is supplied, Conto confirms the record only after the onchain transfer matches the wallet sender, recipient, amount, and currency. Pending transfers return 409 and mismatches return 422. Send txHash for a charge. A session settles from the Tempo escrow channel, not from the agent wallet, so a session record with txHash returns 422. Record a session without it. Reuse the same credentialId and sessionId on retries. A session ID cannot be reused by another agent. Send closeSession: true on a session’s final record. Conto marks the session closed, stops counting it toward MPP_MAX_CONCURRENT_SESSIONS, and releases the unused part of the grant. When the session charged nothing, send amount: 0 with closeSession: true and the grant. Conto closes the session and releases the whole reservation without recording a transaction. Repeating the close returns the same sessionClosed: true response.

Grants and policy bypass

Grants and policy bypass work as they do for x402, with these differences:
  • A charge record must be the grant’s exact amount and use its grant within 10 minutes. A session grant is a ceiling that lasts for the session: each record must fit within what is left of it.
  • A record must use the grant’s sessionId. When the record sends challengeId, it must match the grant’s.
  • The recipient and currency must match the grant. When txHash is supplied, the onchain check uses the grant’s recipient.
A record without a valid grant is recorded, flagged, and alerted as a policy bypass. agentFrozen is true when Conto froze the agent for this bypass. Use optional context.department and context.project values during pre-authorization and recording to apply scoped budgets. Conto persists the same dimensions on the aggregate settlement transaction.

Batch recording

To record several calls settled together, put the total in the top-level fields and each call in batchItems. The items must add up to amount and use unique credentialId values:

Querying services

List the MPP services this agent has paid. Optional period is 24h, 7d (default), 30d, or 90d. Optional limit defaults to 50, max 100. With the SDK, call conto.mpp.services({ period, limit }).

Budget tracking

Check the agent’s MPP spend and limits. With the SDK, call conto.mpp.budget({ sessionId }).
The response has the same shape as the x402 budget. When sessionId is supplied, spend.session reports the call count and amount recorded with that ID.

Supported chain

Conto supports MPP payments on the Tempo blockchain, on testnet and mainnet. The examples on this page use Tempo Testnet.