> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Memory via Walrus

> Give AI agents persistent, encrypted memory that the user's Para wallet owns, using Walrus Memory on Sui.

Combine Para's wallet infrastructure with [Walrus Memory](https://docs.wal.app/walrus-memory/getting-started/what-is-walrus-memory) to give your agents durable, encrypted memory that the user owns through their Para wallet.

## What You'll Learn

* Create a Walrus Memory account owned by a user's Para Sui wallet
* Authorize an agent with a revocable delegate key
* Store and recall agent memory across sessions
* Revoke an agent's access from the Para wallet

This walkthrough covers two integration paths: **app-managed memory**, where your app owns one account and keeps a separate namespace for each Para user, and **user-owned memory**, where each user's Para wallet owns their memory account.

## Why Combine Para and Walrus Memory

| Para Wallets | Walrus Memory |
| - | - |
| Instant onboarding, MPC-secure, white-label | Seal-encrypted memories stored on Walrus |
| Email/social login, no seed phrase or browser extension | Ownership and access control enforced onchain on Sui |
| Embedded Sui wallets that sign through `@mysten/sui` | A revocable delegate key for each agent |
| One login for payments and agent permissions | Semantic recall that works with any model or agent framework |

## Example Use Cases

1. **Agentic Payments**: Let a payments agent remember payees, spending preferences, and approval rules, so users don't repeat them every session.

2. **Recurring Payments**: Keep context about past invoices, billing cycles, and disputes that carries over between runs of a scheduled agent.

3. **Fintech Assistants**: Give in-app assistants long-term memory of a customer's goals and preferences, encrypted and owned by the customer's wallet.

4. **Portable User Memory**: The user's Para wallet owns the memory account and each app or agent is a delegate, so memory follows the user across products instead of staying locked in one.

5. **Multi-Agent Handoff**: Share one memory account across a support agent, a payments agent, and a back-office job, each with its own revocable delegate key.

## What You Need

* **Para SDK** with Sui wallets for your users
* **Walrus Memory SDK**: `@mysten-incubation/memwal` (beta)
* **Sui SDK**: `@mysten/sui` v2 and `@mysten/seal`
* **SUI for gas** (user-owned path only): the user's Para Sui wallet pays gas for the account and delegate key transactions, about 0.005 SUI in total. Fund it with at least 0.01 SUI so the gas budget for creating the account fits.
* **A Walrus Memory relayer**: the [hosted relayer](https://docs.wal.app/walrus-memory/relayer/public-relayer) pays Walrus storage costs. The Walrus Foundation runs it as a public good without an SLA, and it can apply usage limits. You can also [self-host one](https://docs.wal.app/walrus-memory/relayer/self-hosting).

## How It Works

| Role | Who holds it | What it does |
| - | - | - |
| Owner | Your app, or the user's Para Sui wallet | Owns the memory account onchain. Only the owner can add or remove delegate keys. The default client doesn't need it to remember or recall. |
| Delegate | Your agent backend | An Ed25519 key the owner registers on the account. Signs every memory request. Needs no SUI or wallet of its own. |
| Relayer | The Walrus Foundation, or you if you self-host | Embeds each memory, encrypts it with Seal, stores it on Walrus, and pays the storage fees. |
| Namespace | Your app | A label that groups memories inside one account, such as `payments-agent` or one per user. |

The Sui contract records which keys may use an account, and the relayer verifies the delegate key on every request.

> [!WARNING]
>
> The default client sends plaintext to the relayer, which embeds and encrypts it. Keep secrets such as private keys, passwords, and card numbers out of memories. If your compliance model doesn't allow plaintext on the relayer, use the [manual client](https://docs.wal.app/walrus-memory/sdk/usage/memwal-manual) or [self-host the relayer](https://docs.wal.app/walrus-memory/relayer/self-hosting). Namespace names are public onchain, so keep personal data out of them.

## Network Configuration

Use these values for the Walrus Memory contract and hosted relayer on Sui Mainnet.

```bash theme={null}
SUI_FULLNODE_URL=https://fullnode.mainnet.sui.io:443
MEMWAL_RELAYER_URL=https://relayer.memory.walrus.xyz
MEMWAL_PACKAGE_ID=0xe7c16fbea0560e7057e2bf7422feaa4fb313749fc69c9e9092fac7a33b81d7f5
MEMWAL_REGISTRY_ID=0x8bf82c9e09e36b8d1c38298f68b7cb68e7b8762887e7592add9986d5e9cf199f
```

## Step-by-Step Integration

Start with app-managed memory. Choose user-owned memory when users must own their memory and control which agents can use it.

> **Compare the two paths**
>
> | | App-managed memory | User-owned memory |
> | - | - | - |
> | Account owner | Your app | Each user's Para Sui wallet |
> | Gas | Users pay nothing | Each user's wallet pays about 0.005 SUI |
> | Isolation between users | Namespaces, enforced by your server | Separate accounts, enforced onchain |
> | Who revokes an agent | Your app | The user, from their Para wallet |

**App-Managed Memory**

Your app owns one Walrus Memory account and keeps a separate namespace for each Para user. Users don't sign any Sui transactions or hold SUI.

### Step 1: Install Dependencies

```bash npm theme={null}
npm install @mysten-incubation/memwal @mysten/sui @mysten/seal jose
```

```bash yarn theme={null}
yarn add @mysten-incubation/memwal @mysten/sui @mysten/seal jose
```

```bash pnpm theme={null}
pnpm add @mysten-incubation/memwal @mysten/sui @mysten/seal jose
```

```bash bun theme={null}
bun add @mysten-incubation/memwal @mysten/sui @mysten/seal jose
```

### Step 2: Create an Account and Delegate Key

Create your app's account and a delegate key once on the [Walrus Memory dashboard](https://memory.walrus.xyz). Store both values as server-side secrets:

```bash theme={null}
MEMWAL_PRIVATE_KEY=<delegate-private-key-hex>
MEMWAL_ACCOUNT_ID=0x<memwal-account-object-id>
```

`MEMWAL_ACCOUNT_ID` is the account's object ID, not the address of the wallet that owns it. With the owner address, the relayer rejects every request with `401`.

### Step 3: Map Each Para User to a Namespace

Verify the user's [Para session JWT](/v3/react/guides/sessions-jwt) on your server, then derive the namespace from the verified user ID. `PARA_API_KEY_ID` is the `aud` claim of your app's session tokens. Decode one to read it:

```typescript theme={null}
import { createRemoteJWKSet, jwtVerify } from "jose";

const PARA_JWKS = createRemoteJWKSet(
  new URL("https://api.beta.getpara.com/.well-known/jwks.json"), // BETA; use api.getpara.com in PROD
);

// Resolve the Para user from a verified session token, never from the request body
async function namespaceFor(paraJwt: string) {
  const { payload } = await jwtVerify(paraJwt, PARA_JWKS, {
    audience: process.env.PARA_API_KEY_ID!, // the token's aud claim is your Para API key's ID
  });
  return `myapp-${payload.sub}`;
}
```

> [!WARNING]
>
> Namespaces organize data. They don't isolate users from each other, because your delegate key can read every namespace in the account. Always derive the namespace from a verified Para session.

### Step 4: Remember and Recall per User

```typescript theme={null}
import { MemWal } from "@mysten-incubation/memwal";

const memwal = MemWal.create({
  key: process.env.MEMWAL_PRIVATE_KEY!,
  accountId: process.env.MEMWAL_ACCOUNT_ID!,
  serverUrl: "https://relayer.memory.walrus.xyz",
});

const namespace = await namespaceFor(paraJwt); // paraJwt from the request's Authorization header

await memwal.rememberAndWait("Prefers payouts in USDC on Base.", namespace);

const { results } = await memwal.recall({
  query: "What are this user's payout preferences?",
  namespace,
  limit: 5,
});
```

For a full multi-user example, see the [multi-tenant cookbook](https://docs.wal.app/walrus-memory/sdk/cookbook-multi-tenant).

**User-Owned Memory**

The user's Para Sui wallet owns a Walrus Memory account. Your agent backend holds a delegate key that the user authorizes and can revoke at any time.

### Step 1: Install Dependencies

```bash npm theme={null}
npm install @getpara/react-sdk @mysten-incubation/memwal @mysten/sui @mysten/seal
```

```bash yarn theme={null}
yarn add @getpara/react-sdk @mysten-incubation/memwal @mysten/sui @mysten/seal
```

```bash pnpm theme={null}
pnpm add @getpara/react-sdk @mysten-incubation/memwal @mysten/sui @mysten/seal
```

```bash bun theme={null}
bun add @getpara/react-sdk @mysten-incubation/memwal @mysten/sui @mysten/seal
```

### Step 2: Initialize Para and Get a Sui Signer

Complete authentication before signing any transactions.

```typescript theme={null}
import { ParaWeb } from "@getpara/react-sdk";
import { getSuiSigner } from "@getpara/react-sdk/sui/actions";
import { SuiGrpcClient } from "@mysten/sui/grpc";

// Initialize Para (complete authentication before signing)
const para = new ParaWeb("YOUR_PARA_API_KEY");

const suiClient = new SuiGrpcClient({
  network: "mainnet",
  baseUrl: "https://fullnode.mainnet.sui.io:443",
});

// A @mysten/sui Signer backed by the user's Para Sui wallet
const signer = await getSuiSigner({ para, client: suiClient });
```

> [!TIP]
>
> In a React app, pass the same `para` instance to `ParaProvider` as `paraClientConfig`. Inside components, `useParaSuiSigner({ client: suiClient })` from `@getpara/react-sdk` returns the same signer as `suiSigner`.

### Step 3: Adapt the Signer for Walrus Memory

The Walrus Memory account helpers expect a wallet-adapter signer that executes transactions on its own. Wrap the Para signer so it uses your Sui client:

```typescript theme={null}
import type { Transaction } from "@mysten/sui/transactions";

const walletSigner = {
  address: signer.toSuiAddress(),
  signAndExecuteTransaction: ({ transaction }: { transaction: Transaction }) =>
    signer.signAndExecuteTransaction({ transaction, client: suiClient }),
  signPersonalMessage: ({ message }: { message: Uint8Array }) =>
    signer.signPersonalMessage(message),
};
```

> [!WARNING]
>
> Don't pass the Para signer to Walrus Memory directly. Walrus Memory calls `signAndExecuteTransaction` without a Sui client, and the transaction fails to build.

### Step 4: Generate the Agent's Delegate Key

Run this on your agent backend. The private key never leaves your server. Send only the public key to the client.

```typescript theme={null}
import { generateDelegateKey } from "@mysten-incubation/memwal/account";

const delegate = await generateDelegateKey();

// Keep delegate.privateKey in your secrets store, keyed by the Para user.
// Return only the public key to the client.
const agentPublicKey = Buffer.from(delegate.publicKey).toString("hex");
```

> [!WARNING]
>
> The delegate key is a bearer credential: anyone who holds it can read and write the account's memory until the user removes it. To rotate it, generate a new key, authorize it with `addDelegateKey`, switch the agent to it, then remove the old key (Step 7).

### Step 5: Create the Memory Account and Authorize the Agent

The user's Para wallet signs both transactions. Pass `suiClient` to each call so the transactions run on the network your client targets.

```typescript theme={null}
import { createAccount, addDelegateKey } from "@mysten-incubation/memwal/account";

// Walrus Memory contract on Sui
const MEMWAL_PACKAGE_ID = "0xe7c16fbea0560e7057e2bf7422feaa4fb313749fc69c9e9092fac7a33b81d7f5";
const MEMWAL_REGISTRY_ID = "0x8bf82c9e09e36b8d1c38298f68b7cb68e7b8762887e7592add9986d5e9cf199f";

// Read the account ID from the AccountCreated event the owner's address emitted
async function findAccountId(owner: string) {
  const query = `{
    events(last: 1, filter: {
      type: "${MEMWAL_PACKAGE_ID}::account::AccountCreated",
      sender: "${owner}"
    }) { nodes { contents { json } } }
  }`;
  const { data } = await fetch("https://graphql.mainnet.sui.io/graphql", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ query }),
  }).then((res) => res.json());
  return data.events.nodes[0]?.contents.json.account_id as string | undefined;
}

// One account per Sui address: reuse it, or create it once and store accountId with the user
let accountId = await findAccountId(walletSigner.address);
if (!accountId) {
  const created = await createAccount({
    packageId: MEMWAL_PACKAGE_ID,
    registryId: MEMWAL_REGISTRY_ID,
    walletSigner,
    suiClient,
  });
  accountId = created.accountId;
}

// Authorize the agent's delegate key to read and write this account's memory
await addDelegateKey({
  packageId: MEMWAL_PACKAGE_ID,
  registryId: MEMWAL_REGISTRY_ID,
  accountId,
  publicKey: agentPublicKey, // from Step 4
  label: "Payments agent",
  walletSigner,
  suiClient,
});
```

Send `accountId` to your agent backend. Each Sui address can own one account, so `findAccountId` lets a repeat run reuse it. Without the lookup, a second `createAccount` call for the same user fails with abort code `3` (`EAccountAlreadyExists`) before it executes. Give each agent its own delegate key, up to 20 per account.

> [!NOTE]
>
> The hosted relayer's `GET /api/accounts/{owner}/exists` answers only `true` or `false`, and its CORS policy allows only the Walrus Memory dashboard. Call it from your server, not the browser.

### Step 6: Remember and Recall from the Agent

On your agent backend, create a Walrus Memory client with the delegate key and the user's account ID:

```typescript theme={null}
import { MemWal } from "@mysten-incubation/memwal";

const memwal = MemWal.create({
  key: delegatePrivateKey, // from Step 4
  accountId, // from Step 5
  serverUrl: "https://relayer.memory.walrus.xyz",
  namespace: "payments-agent",
});

// Store a fact the agent learned, and wait until it is on Walrus
await memwal.rememberAndWait(
  "Pays monthly rent of 1,800 USDC to their landlord on the 1st. Asks for confirmation above 500 USDC.",
);

// Recall relevant context before the agent acts
const { results } = await memwal.recall({
  query: "What recurring payments and approval rules does this user have?",
  limit: 5,
});

const context = results.map((memory) => memory.text).join("\n");
```

The client also offers `analyze(text)` to extract separate facts from a longer conversation, `rememberBulk` for up to 20 memories per request, `recall({ query, sort: "recent" })` when the newest match matters more than the closest one, and `health()` to check the relayer.

If you use the Vercel AI SDK, `withMemWal` from `@mysten-incubation/memwal/ai` recalls memories before each generation and saves new facts afterward. See [AI Integration](https://docs.wal.app/walrus-memory/sdk/usage/with-memwal). For MCP clients such as Claude Code, Codex, and Cursor, the [Walrus Memory MCP server](https://docs.wal.app/walrus-memory/mcp/overview) provides tools such as `memwal_remember` and `memwal_recall`, with a delegate key for each client.

> [!NOTE]
>
> The [manual client](https://docs.wal.app/walrus-memory/sdk/usage/memwal-manual) signs Seal session keys with a Sui private key or a `walletSigner`. With the user's Para wallet as the `walletSigner`, each `recallManual` call that finds memories creates a new session key, so every recall asks the wallet for a signature.

### Step 7: Revoke the Agent

The user can remove the agent's delegate key from their Para wallet at any time:

```typescript theme={null}
import { removeDelegateKey } from "@mysten-incubation/memwal/account";

await removeDelegateKey({
  packageId: MEMWAL_PACKAGE_ID,
  registryId: MEMWAL_REGISTRY_ID,
  accountId,
  publicKey: agentPublicKey,
  walletSigner,
  suiClient,
});
```

> [!NOTE]
>
> Removing the key blocks the agent's relayer access, and the memories stay in the account for any other delegate key the user authorizes. Removal is forward-only for encryption: memories saved before removal stay decryptable with Seal keys the agent already fetched, until they're re-encrypted. To cut off every key at once, the owner can [deactivate the account](https://docs.wal.app/walrus-memory/contract/delegate-key-management).

## Related Resources

<picture>![Walrus Memory](/images/v3/cards/partner-walrus.png)</picture>

## [Walrus Memory](https://docs.wal.app/walrus-memory/getting-started/what-is-walrus-memory)

Concepts, SDK reference, and relayer setup for Walrus Memory

<picture>![Para Sui Signer](/images/v3/cards/chain-sui.png)</picture>

## [Para Sui Signer](/v3/references/actions/signer-integrations/sui/get-sui-signer)

Create a @mysten/sui signer backed by a Para wallet

<picture>![Eliza AI Agent Integration](/images/v3/cards/para-with-eliza.png)</picture>

## [Eliza AI Agent Integration](/v3/walkthroughs/Eliza)

Build wallet-enabled AI agents with Para and Eliza OS


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.