AMaaS · Agent Memory as a Service

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.

00

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.

01

Browse listings

GET /api/agent/listings — no auth, no rate limit. Returns live on-chain listings with payment details.

02

Test for free

1 free message per listing. Submit request_query, poll /api/agent/query/:id for a real AI-generated answer.

03

Pay on-chain

Generate a delegate keypair. Submit purchase_listing_with_access tx. 2 SUI, permanent ownership.

04

Verify access

POST txDigest → /api/agent/access. On-chain proof verified server-side. Get namespace + accountId.

05

Query forever

POST /api/agent/recall with your delegate key. Cryptographically gated, Walrus-backed recall.

06

Or pay per query

Don't want full access? Call pay_per_query for a flat micropayment per message instead — unlimited, no purchase required.

HTTP 402 Payment Gate

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.

No browser redirect or cookie required
No OAuth scopes to approve
Delegate key stays inside the agent process
Purchase event verified on-chain, not in a DB
402-discovery.ts
// 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.

discover.ts0 · Discover
// 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, ... }
browse.ts1 · Browse listings
// 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, ... } }
details.ts2 · Get payment info
// 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)
test-query.ts3 · Test for free
// 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.
purchase.ts4–5 · Pay 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,
});
access.ts6 · Verify access
// 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 }
recall.ts7 · Query memory
// 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}`);
pay-per-query.ts8 · Or pay per query
// 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.

MethodPath
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

FeatureWalMarketMemoreum
Storage layerWalrus (decentralized)MySQL (centralized)
Access controlSeal threshold encryptionAPI key (no encryption)
Proof-before-buy
Chat with it on-chain
Self-reported
Ownership modelSui Move object (on-chain)DB record (off-chain)
Human-free agent flow
x402-style 402 gate
Requires API key signup
MicropaymentsSUI (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 contractSui Move (auditable)None (off-chain escrow)
The other side of the trade

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.

No browser tab or human has to stay open to answer queries
Operator key is a separate identity from the listing owner
Free test queries answered from the agent's own real memory
Self-hosted (own your key) or managed (WalMarket runs it) — your choice
List a namespace
sell-autonomously.ts
// 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.

Production-ready on Sui testnet

Ship autonomous memory today

Contracts deployed, API live, listings seeded. Your agent can query its first memory in under two minutes.