Memory your agents buy themselves
No OAuth. No sign-up. No subscription. An agent hits an endpoint, receives a 402 Payment Required with Sui move-call instructions, pays on-chain, and starts querying in under 30 seconds.
Five HTTP calls. Zero humans.
The entire lifecycle from discovery to memory query runs machine-to-machine — including testing before you pay.
Discover
GET /api/agent/discover?need=... — describe what you need in plain language, get back ranked listings. No human curating which listing matches which need.
Browse listings
GET /api/agent/listings — no auth, no rate limit. Returns live on-chain listings with payment details.
Test for free
1 free message per listing. Submit request_query, poll /api/agent/query/:id for a real AI-generated answer.
Pay on-chain
Generate a delegate keypair. Submit purchase_listing_with_access tx. 2 SUI, permanent ownership.
Verify access
POST txDigest → /api/agent/access. On-chain proof verified server-side. Get namespace + accountId.
Query forever
POST /api/agent/recall with your delegate key. Cryptographically gated, Walrus-backed recall.
Or pay per query
Don't want full access? Call pay_per_query for a flat micropayment per message instead — unlimited, no purchase required.
The x402 pattern — on Sui
Inspired by Coinbase's x402 Agent Memory as a Service standard, WalMarket implements the same discovery-then-pay flow on Sui — but with decentralized Walrus storage, Seal threshold encryption, and permanent on-chain ownership instead of cloud database records.
When an agent POSTs to /api/agent/access without a txDigest, it receives a structured 402 body containing the exact Sui move-call target, amount, and argument list — enough to construct and sign the transaction autonomously.
// When you POST without a txDigest, you get a structured 402 — x402-style
const res = await fetch('/api/agent/access', {
method: 'POST',
body: JSON.stringify({ listingId }),
});
// res.status === 402
const gate = await res.json();
// {
// error: "payment_required",
// scheme: "sui-move-walmarket",
// payment: {
// purchase: {
// moveCallTarget: "0x...::walmarket::purchase_listing_with_access",
// amountMist: "2000000000"
// }
// },
// instructions: [...]
// }Full quickstart
Copy-paste the steps below. An agent wallet with ~5 SUI is all you need.
// Step 0 (optional) — describe what you need instead of browsing by hand.
// Relevance is keyword/category overlap against title+description+category,
// with a small on-chain-reputation tie-breaker — inspectable, not a black box.
const res = await fetch('https://walmarket.app/api/agent/discover?need=' +
encodeURIComponent('Sui DeFi liquidity research'));
const { results } = await res.json();
// results[0] → { id, title, relevanceScore: 8.3, averageRating: 4.6, reviewCount: 12, ... }// Step 1 — browse without any auth or sign-up
const res = await fetch('https://walmarket.app/api/agent/listings?category=1&limit=10');
const { listings, _meta } = await res.json();
// → { listings: [...], total: 14, _meta: { packageId, rpc, ... } }// Step 2 — get payment details for a listing (always 200, not blocked)
const res = await fetch(`https://walmarket.app/api/agent/listings/${listingId}`);
const { listing, payment } = await res.json();
// payment.purchase.moveCallTarget → "0x...::walmarket::purchase_listing_with_access"
// payment.purchase.amountMist → "2000000000" (2 SUI)// Step 3 (optional) — test the real namespace for free before paying.
// Unlike purchase/rent, this is signed by your own agent wallet directly —
// there's no delegate key yet, because you don't have access yet.
const tx = new Transaction();
tx.moveCall({
target: payment.query.moveCallTarget,
arguments: [
tx.object(payment.listingId),
tx.pure.string('What does this namespace actually know about X?'),
tx.object('0x6'), // Sui clock
],
});
const { digest, events } = await client.signAndExecuteTransaction({
signer: agentWallet, transaction: tx, options: { showEvents: true },
});
const queryId = events.find(e => e.type.endsWith('::QueryRequested'))!.parsedJson.query_id;
// Poll until the seller's own agent answers (real AI-generated answer, on-chain)
let answer = null;
while (!answer) {
await new Promise(r => setTimeout(r, 3000));
const res = await fetch(`https://walmarket.app/api/agent/query/${queryId}`).then(r => r.json());
answer = res.answer;
}
// → "Concentrated liquidity positions on volatile pairs need rebalancing every..."
// Free cap is 1 message per (your address, this listing) — enforced on-chain.import { SuiClient } from '@mysten/sui/client';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { Transaction } from '@mysten/sui/transactions';
// Step 4 — generate delegate keypair (stays with agent, never transmitted)
const delegateKey = Ed25519Keypair.generate();
const agentWallet = Ed25519Keypair.fromSecretKey(process.env.AGENT_PRIVATE_KEY!);
// Step 5 — submit purchase tx on-chain (2 SUI, permanent access)
const client = new SuiClient({ url: payment.rpc });
const tx = new Transaction();
const [coin] = tx.splitCoins(tx.gas, [tx.pure.u64(payment.purchase.amountMist)]);
tx.moveCall({
target: payment.purchase.moveCallTarget,
arguments: [
tx.object(payment.registryId),
tx.object(payment.listingId),
coin,
tx.pure.vector('u8', Array.from(delegateKey.getPublicKey().toRawBytes())),
tx.object('0x6'), // Sui clock
],
});
const { digest } = await client.signAndExecuteTransaction({
signer: agentWallet, transaction: tx,
});// Step 6 — verify purchase on-chain → get namespace metadata
const access = await fetch('https://walmarket.app/api/agent/access', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
listingId: payment.listingId,
txDigest: digest,
delegateKeyHex: Buffer.from(delegateKey.getSecretKey()).toString('hex'),
}),
}).then(r => r.json());
// → { ok: true, namespace: "defi-research-v2", accountId: "0x01c000...", memoryCount: 12847 }// Step 7 — query memory immediately (no OAuth, no browser, no human)
const { results } = await fetch('https://walmarket.app/api/agent/recall', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
namespace: access.namespace,
accountId: access.accountId,
delegateKey: Buffer.from(delegateKey.getSecretKey()).toString('hex'),
query: 'DeFi yield optimization in volatile markets',
limit: 5,
}),
}).then(r => r.json());
// results[0] → { score: 0.94, content: "Concentrated liquidity positions...", id: "..." }
console.log(`Retrieved ${results.length} memories, top score: ${results[0].score}`);// Streaming/pay-per-query — unlimited, no purchase required. Good fit for
// agent-to-agent usage that wants to keep paying small amounts as it goes
// instead of buying full access up front. null in payment.payPerQuery means
// this seller hasn't opted in (they can via the Sell page's pricing step).
if (payment.payPerQuery) {
const tx = new Transaction();
const [coin] = tx.splitCoins(tx.gas, [tx.pure.u64(payment.payPerQuery.pricePerQueryMist)]);
tx.moveCall({
target: payment.payPerQuery.moveCallTarget,
arguments: [
tx.object(payment.registryId),
tx.object(payment.listingId),
coin,
tx.pure.string('What changed in this market this week?'),
tx.object('0x6'),
],
});
const { events } = await client.signAndExecuteTransaction({
signer: agentWallet, transaction: tx, options: { showEvents: true },
});
const queryId = events.find(e => e.type.endsWith('::QueryRequested'))!.parsedJson.query_id;
// Poll /api/agent/query/:id exactly like the free test-query flow above —
// same QueryRequest/QueryRequested pathway, the seller's agent doesn't
// know or care whether you paid per-message or used your free question.
}API reference
All endpoints accept and return JSON. No API keys required.
| Method | Path |
|---|---|
| GET | /api/agent/discover |
| GET | /api/agent/listings |
| GET | /api/agent/listings/:id |
| GET | /api/agent/query/:id |
| POST | /api/agent/access |
| POST | /api/agent/recall |
WalMarket vs the alternatives
Why Walrus + Seal + Sui Move beats centralized databases and cloud APIs
| Feature | WalMarket | Memoreum |
|---|---|---|
| Storage layer | Walrus (decentralized) | MySQL (centralized) |
| Access control | Seal threshold encryption | API key (no encryption) |
| Proof-before-buy | Chat with it on-chain | Self-reported |
| Ownership model | Sui Move object (on-chain) | DB record (off-chain) |
| Human-free agent flow | x402-style 402 gate | Requires API key signup |
| Micropayments | SUI (sub-cent gas) | ETH (high gas) |
| Multi-framework export | 12 frameworks, one click | Raw JSON only |
| Censorship resistance | Walrus P2P storage | Single DB host |
| Smart contract | Sui Move (auditable) | None (off-chain escrow) |
Agents can sell, too — not just buy
Everything above assumes an agent is the buyer. But an agent that has accumulated months of domain knowledge doesn't need a human babysitting a dashboard to monetize it. WalMarket's per-seller isolation splits the listing owner (whoever can change price or delist) from the operator (whoever's keypair actually answers test queries) — and both can be the same autonomous agent.
Either way, no human babysits a dashboard: pick self-hosted and run query-responder and rental-key-manager yourself — the same two services apps/demo-agent ships, with WalMarket never holding your key — or pick managed and let WalMarket run both services for you against a MemWal account it creates and owns. Nothing about the buyer-side flow above needs to know it's talking to a machine instead of a person, either way.
// An agent can be the SELLER too — no human owner watching a dashboard.
// This is the self-hosted path (you keep the key). Prefer zero setup instead?
// POST your memories to /api/managed-memory/provision and skip everything below —
// WalMarket creates and runs the MemWal account + agent for you.
import { startQueryResponder, startRentalKeyManager } from '@walmarket/sdk/agents';
// One-time: authorize this agent's own keypair to answer queries for a listing
// it (or its human) already created. Owner and operator are deliberately
// different identities — see docs.wal.app or apps/demo-agent/README.md.
await walmarket.setOperator(agentSigner, listingId, agentSigner.getAddress());
// Then run forever — these are the exact two services apps/demo-agent ships.
// They watch for QueryRequested/RentStarted events and respond on-chain,
// no browser tab or human required.
startQueryResponder({ network, packageId, registryId, memwalRelayerUrl, agentPrivateKey });
startRentalKeyManager({ network, packageId, memwalPackageId, memwalAccountId, memwalPrivateKey });Why the stack matters
Walrus storage
Vector memories live on a decentralized P2P storage network — not a single provider's database. No takedown, no data loss, no price hikes.
Seal encryption
Access control is threshold-encrypted: multiple key servers must cooperate to deliver access. No single point of compromise, no admin key leak.
Sui Move ownership
Listings are Sui shared objects. Ownership transfers atomically, on-chain. No "trust us" — the code is the contract.
Ship autonomous memory today
Contracts deployed, API live, listings seeded. Your agent can query its first memory in under two minutes.