Building on the Agentic L1: A Developer’s Guide to Somnia Agents
A practical introduction to building with Somnia Agents ahead of the Somnia Agentathon.
The Agentathon kicks off on May 20. If you’re building on Somnia, it’s a good forcing function to ship a complete integration: contracts are deterministic, but they can’t fetch APIs, read web pages, or run non-deterministic compute. Somnia Agents fill that gap with validator-executed, consensus-verified compute and an async callback back into your contract.
This guide is a practical quick-start: the agent call flow, the three primitives you’ll use most, and demo-ready use cases.
Why Smart Contracts Need Agents
A smart contract can do math. It can move tokens. It can branch on chain state.
What it can’t do, natively:
Fetch a price from an API
Read a webpage
Ask an LLM to classify text
Make any decision that requires external information or AI reasoning.
For more than a decade, the workaround has been oracles. You bolt a centralized service onto your decentralized contract, trust that service to behave, and accept the resulting architecture: a trustless contract leashed to a trusted middleman.
Somnia Agents change this. They give smart contracts native access to external data, web extraction, and on-chain LLM inference. All executed by Somnia’s validator network and verified by consensus, just like any other piece of on-chain state.
What Is a Somnia Agent
A Somnia Agent is a decentralized, sandboxed compute container addressable by agentId. Your contract invokes it the same way it would call any other contract (with an ABI-encoded payload) except execution happens off the EVM, on a subcommittee of validators. The result returns asynchronously via a callback.
Three properties make this work:
EVM-native interface: agent calls are just ABI calldata.
Deterministic AI: LLM agents run with fixed seeds and
temperature = 0, so every validator independently produces byte-identical outputs. That’s how consensus on AI results is reached.Asynchronous by design:
createRequestreturns arequestIdimmediately. The actual result lands later in a callback you implement.
The Three Base Agents
The platform currently exposes three base agents. All three are live on both Testnet and Mainnet (same agentId on both networks), only the platform contract address differs.
JSON API Request: 0.03 per validator
Fetches and parses any public HTTP endpoint. Pull a price feed, query a sports API, read a weather service - without an off-chain relayer.
fetchUint(
"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd",
"bitcoin.usd",
uint8(8)
);Selector syntax is JSON-path-like (bitcoin.usd, items.0.name). The agent also exposes typed variants for strings, addresses, and arrays.
Use for: price oracles, sports / event resolution, weather feeds, public data lookups.
LLM Inference: 0.07 per validator
Runs deterministic inference against an on-chain Qwen3-30B model. Four functions, increasing in power:
inferString: single-turn classification, constrainable to allowed values.inferNumber: single-turn integer output, clamped to a range.inferChat: multi-turn chat with message history.inferToolsChat: multi-turn chat with MCP tool calling and on-chain tool calling (the model yields calldata back to your contract).
Use for: content moderation, sentiment scoring, intent classification, agentic DeFi bots, autonomous routing logic.
LLM Parse Website: 0.10 per validator
Scrapes a URL and extracts structured data via LLM. Two modes:
Direct mode: scrape this specific URL and extract these fields.
Search mode: search this domain for content matching this query, then extract.
Use for: prediction market resolution, news-driven triggers, structured extraction from sites without an API.
Your First Agent Call
Here is a complete BTC price oracle. It requests the price via the JSON API agent, stores it on the callback, and is the canonical “first integration” for a reason, every other agent call follows the same shape.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {
IAgentRequester,
IAgentRequesterHandler,
Response,
Request,
ResponseStatus
} from "./interfaces/IAgentRequester.sol";
interface IJsonApiAgent {
function fetchUint(string calldata url, string calldata selector, uint8 decimals)
external returns (uint256);
}
contract BtcPriceOracle is IAgentRequesterHandler {
IAgentRequester public immutable platform;
uint256 public constant JSON_API_AGENT_ID = 13174292974160097713;
uint256 public constant SUBCOMMITTEE_SIZE = 3;
uint256 public constant PRICE_PER_AGENT = 0.03 ether;
uint256 public latestPrice;
mapping(uint256 => bool) public pendingRequests;
event PriceReceived(uint256 indexed requestId, uint256 price);
constructor(address platform_) {
platform = IAgentRequester(platform_);
}
function requestBitcoinPrice() external payable returns (uint256 requestId) {
bytes memory payload = abi.encodeWithSelector(
IJsonApiAgent.fetchUint.selector,
"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd",
"bitcoin.usd",
uint8(8)
);
uint256 deposit = platform.getRequestDeposit()
+ PRICE_PER_AGENT * SUBCOMMITTEE_SIZE;
require(msg.value >= deposit, "Underfunded");
requestId = platform.createRequest{value: deposit}(
JSON_API_AGENT_ID,
address(this),
this.handleResponse.selector,
payload
);
pendingRequests[requestId] = true;
}
function handleResponse(
uint256 requestId,
Response[] memory responses,
ResponseStatus status,
Request memory /* details */
) external override {
require(msg.sender == address(platform), "Only platform");
require(pendingRequests[requestId], "Unknown request");
delete pendingRequests[requestId];
if (status == ResponseStatus.Success && responses.length > 0) {
latestPrice = abi.decode(responses[0].result, (uint256));
emit PriceReceived(requestId, latestPrice);
}
}
receive() external payable {}
}Deploy it pointing at the testnet platform address (0x037Bb9C718F3f7fe5eCBDB0b600D607b52706776), fund it with STT, and call requestBitcoinPrice() with at least 0.12 STT attached. The callback fires within seconds.
Four Tips That Save Hours
Most stuck integrations come down to the same handful of mistakes. Fix these up front.
1. Send the right deposit.
getRequestDeposit() returns the operations-reserve floor, not the practical deposit. Sending only the floor sets the per-agent budget to zero, runners skip your request, and it times out. Always add pricePerAgent × subcommitteeSize on top:
msg.value ≥ getRequestDeposit() + pricePerAgent × subcommitteeSizeFor a JSON API call with the default subcommittee of 3: 0.03 + 0.03 × 3 = 0.12 STT.
2. Implement receive() external payable.
Rebates are pushed automatically on finalisation. Without receive(), the transfer fails silently and the funds stick in the platform contract.
3. Gate your callback.
handleResponse is external. Anyone can call it. Always:
require(msg.sender == address(platform), "Only platform");
require(pendingRequests[requestId], "Unknown request");4. Handle every status.
A request can end in Success, Failed, or TimedOut. Decoding responses[0].result on a non-Success callback panics. Check the status, then decode.
Five Use Cases That Only Work on an Agentic L1
Each of these needs all three pieces: data + reasoning + on-chain action. It would be impractical without a deterministic, validator-verified agent layer. Pick one and bring it to the Agentathon.
1. AI-Resolved Prediction Markets
Use LLM Parse Website to read a news source or official results page and resolve a market in a single transaction. No human resolvers, no multisig oracle, no manual settlement. The receipt gives anyone an auditable trail of what the agent read and how it decided.
2. Autonomous Content Moderation
A social or forum contract uses LLM Inference (inferString with allowedValues = ["safe","unsafe"]) to classify every post on submission. Unsafe posts revert. Moderation logic lives in the contract, not in a Discord room.
3. Self-Updating Dynamic NFTs
An NFT whose metadata responds to real-world data: weather in a city, sports team performance, election odds. JSON API Request fetches the data; LLM Inference interprets it into a trait or rarity update. Every change is on-chain and verifiable, not just an off-chain image swap.
4. Agentic DeFi Bots
Use inferToolsChat to give an LLM a budget and a goal (“rebalance my position above 1.5x collateral, swap to USDC if ETH drops below $X”). The model decides which DEX to call and yields the calldata back to your contract, which executes it. The user controls the strategy; the agent does the work.
5. Cross-Site Data Aggregators
A “trustless rating” contract that pulls reviews from multiple sources via LLM Parse Website, scores sentiment via LLM Inference, and publishes an aggregate. Everything verifiable, everything on-chain. No centralized data provider in between.
Getting Started
The agents are live, the docs are public, and the platform contract is one createRequest away.
To get the most out of the Agentathon, show up with a tiny end-to-end demo already working: one request, one callback, one state update. Then you can spend the week iterating on product logic instead of debugging setup.
Somnia Agents docs: https://docs.somnia.network/agents
Testnet Agent Explorer: https://agents.testnet.somnia.network/ (browse agents + generate Solidity/TypeScript snippets)
Ready to build? Join the Agentathon and ship an agent-powered contract end-to-end.


