Access Dune’s API with pay-per-request micropayments using the Machine Payment Protocol.
MPP (Machine Payment Protocol) is an open standard for machine-to-machine HTTP micropayments built on the HTTP 402 challenge-response flow. Dune’s MPP integration lets agents pay per-request through a payment channel - no API keys, no user account, and no credit card required.
The fastest way to get started. Ask your AI coding agent to set up Tempo and run a query on Dune - no manual code required. This works with any agent that supports skills or tool use, including Claude Code, Cursor, OpenAI Codex, OpenCode, and others.
Always ask your agent to close the session when you are done. Closing the session settles the payment channel on-chain and refunds any reserved funds back to your wallet - you are only charged for what you actually used.
When you are finished querying, tell your agent:
Close the tempo session.
This ensures your unspent deposit is returned promptly. If you forget to close, funds remain in escrow until the channel expires.
For full control, you can integrate MPP directly into your application using the mppx client library and viem for EVM account management. The mppx session API wraps the standard fetch and handles the 402 negotiation, channel management, spend tracking, and payment signing transparently.
Step 2 - Set up your wallet and initialize a session
Create an account from a private key and initialize a Tempo session. The maxDeposit parameter sets the maximum amount (in USD) to escrow when a payment channel is opened.
import { tempo } from "mppx/client";import { privateKeyToAccount } from "viem/accounts";const account = privateKeyToAccount( process.env.PRIVATE_KEY as `0x${string}`);const session = tempo.session({ account, maxDeposit: "10" });
Use session.fetch exactly like the standard Fetch API. On the first call, the session intercepts the 402 response, opens a Tempo payment channel, and retries the request with a valid payment credential - all transparently.
Dune executes queries asynchronously. Poll the status endpoint until the state is QUERY_STATE_COMPLETED.
let state = "";do { const r = await session.fetch( `https://api.dune.com/api/v1/execution/${execution_id}/status` ); state = ((await r.json()) as { state: string }).state; if (state === "QUERY_STATE_FAILED") throw new Error("Query failed"); if (state !== "QUERY_STATE_COMPLETED") await new Promise((r) => setTimeout(r, 2_000));} while (state !== "QUERY_STATE_COMPLETED");