SDK Docs

SDK Documentation

Creating agents, the guardrail policy surface, swaps and payments, Umbra stealth addresses, and the security model.

SOLAI SDK — Documentation

Status Chain Custody

A non-custodial DeFi SDK on Solana. Create AI agents that handle swaps and payments on a user's behalf — bounded by guardrails the user sets, with Umbra-based stealth addresses for private payments.

Preview documentation. The SDK is in private beta and the API surface described here may change before public release. Join the early-access list to get the docs and your private npm tag when your batch opens.


Why an SDK

Autonomous agents are useful exactly when they can act without asking. That is also what makes them dangerous: an agent with unlimited authority is a hot wallet with extra steps.

SOLAI splits the difference. An agent gets real signing capability, but only inside a policy the user writes and signs. Spending limits, token allowlists, protocol allowlists. Anything outside the policy is refused at the SDK boundary — before a transaction is built, before a fee is paid, before anything reaches the chain.

Three properties hold throughout:

  • Non-custodial — keys never leave the user's device and never touch your servers or ours.
  • Bounded — the policy is the agent's entire authority, and it is revocable.
  • Private — payments can route through fresh stealth addresses so a user's main wallet is never exposed on-chain.

Installation

npm i @solai/sdk
pnpm add @solai/sdk

The SDK is written in TypeScript and ships its own types. It targets Node 18+ and modern browsers.


Quickstart

import { Solai } from "@solai/sdk";

const solai = new Solai({ wallet, cluster: "mainnet-beta" });

// The user signs this policy. It is the agent's entire authority.
const agent = await solai.agents.create({
  name: "treasury-bot",
  policy: {
    dailyLimit: "500 USDC",
    perTxLimit: "100 USDC",
    tokens:    ["SOL", "USDC", "JUP"],
    protocols: ["jupiter", "kamino"],
    revocable: true,
  },
});

// Swap — the route is found for you, the policy is checked first.
await agent.swap({ from: "USDC", to: "SOL", amount: 50 });

// Pay privately — a fresh stealth address, every time.
await agent.pay({
  to: "alice.sol",
  amount: 12,
  token: "USDC",
  stealth: true,
});

Initialization

Solai is the entry point. It needs a wallet adapter to request signatures from and a cluster to talk to.

const solai = new Solai({
  wallet,                    // any Solana wallet adapter
  cluster: "mainnet-beta",   // "mainnet-beta" | "devnet" | "testnet"
  rpcUrl,                    // optional — your own RPC endpoint
});
OptionTypeDescription
walletWalletAdapterThe user's wallet. Signing requests are routed here.
clusterClusterWhich Solana cluster to target. Defaults to mainnet-beta.
rpcUrlstringCustom RPC endpoint. Falls back to a public endpoint.

Guardrails

The policy is the core of the SDK. It is signed by the user at agent-creation time and enforced on every call.

Policy fields

FieldTypeDescription
dailyLimitstringTotal value the agent may move in a rolling 24 hours.
perTxLimitstringCeiling on any single transaction the agent builds.
tokensstring[]Mints the agent may hold, send, or swap. Everything else is refused.
protocolsstring[]Venues the agent may route through — jupiter, kamino, or your own program.
expiresAtDateHard expiry. After this the policy stops authorising anything.
revocablebooleanWhether the user can tear the agent's authority down instantly.

How enforcement works

Every agent method runs the same three steps before it signs anything:

  1. Resolve the intent into a concrete transaction — amounts, route, destination.
  2. Check that transaction against the policy: value against the limits, every mint against tokens, every program against protocols, and the clock against expiresAt.
  3. Sign and send only if all checks pass. Otherwise throw a PolicyViolationError and build nothing.

Because the check happens before the transaction is built, a refused call costs no fee and leaves no on-chain trace.

try {
  await agent.send({ to: "…", amount: 900, token: "USDC" });
} catch (err) {
  if (err instanceof PolicyViolationError) {
    console.log(err.reason);  // "exceeds dailyLimit (500 USDC)"
    console.log(err.field);   // "dailyLimit"
  }
}

Worked examples

RequestVerdict
swap 50 USDC → SOL via JupiterAllowed — within limits, both mints allowlisted, Jupiter allowlisted
pay 12 USDC to alice.solAllowed
send 900 USDCRefused — exceeds dailyLimit (500 USDC)
swap SOL → BONKRefused — BONK is not in tokens

Revoking

await agent.revoke();

Revocation is immediate and unilateral. A revoked agent's policy authorises nothing; subsequent calls throw regardless of their contents.


Agents

Creating

const agent = await solai.agents.create({ name, policy });

Listing and loading

const agents = await solai.agents.list();
const agent  = await solai.agents.get(agentId);

Updating a policy

Tightening a policy takes effect immediately. Loosening one requires a fresh signature from the user, because it grants authority they have not yet approved.

await agent.updatePolicy({ dailyLimit: "250 USDC" });  // tighten — immediate
await agent.updatePolicy({ dailyLimit: "900 USDC" });  // loosen — prompts the user

Actions

Swap

Routes across Solana DEXs and executes at the best available rate.

await agent.swap({
  from: "USDC",
  to: "SOL",
  amount: 50,
  slippageBps: 50,   // optional, defaults to 50 (0.5%)
});

Pay

A one-off transfer to a wallet address or a resolvable handle.

await agent.pay({
  to: "alice.sol",
  amount: 12,
  token: "USDC",
  stealth: true,     // derive a fresh one-time address
});

Schedule

Recurring transfers on a cadence. The agent executes them without re-prompting, still inside the policy.

await agent.schedule({
  to: "alice.sol",
  amount: 5,
  token: "USDC",
  cadence: "daily",
  startsAt: new Date(),
});

Conditional orders

Execute when a price condition is met.

await agent.when({
  asset: "SOL",
  condition: { type: "priceDrop", percent: 10 },
  then: { action: "swap", from: "USDC", to: "SOL", amount: 100 },
});

Stealth payments

SOLAI uses Umbra-style stealth addresses so a payment can be received without linking to the recipient's main wallet.

How it works

  1. Publish a meta-address. The recipient generates one shareable meta-address, once.
  2. Derive. The sender derives a unique one-time address from that meta-address via X25519 ECDH. Only the recipient can compute the matching private key.
  3. Send. Funds land at the one-time address. Nothing on-chain links it to the recipient's main wallet.
  4. Scan and sweep. The recipient scans for incoming stealth payments and sweeps them whenever they choose.
// Recipient — once
const meta = await solai.stealth.createMetaAddress();

// Sender
await agent.pay({ to: meta, amount: 12, token: "USDC", stealth: true });

// Recipient — discover and collect
const payments = await solai.stealth.scan();
await solai.stealth.sweep(payments);

Every payment produces a fresh address. There is no address reuse, so no observer can aggregate a recipient's payment history from the chain.


x402 micropayments

The SDK implements the x402 protocol, which carries payment over the HTTP 402 Payment Required status. It suits machine-scale payments — per-request API billing, metered inference, pay-per-call services — where a human confirmation step would be absurd.

const response = await agent.x402.fetch("https://api.example.com/inference", {
  maxAmount: "0.01 USDC",
});

The maxAmount ceiling is checked against the policy like any other spend, and the per-request amounts still count toward dailyLimit.


Error handling

ErrorMeaning
PolicyViolationErrorThe request fell outside the agent's policy. Carries reason and field.
AgentRevokedErrorThe agent's authority has been revoked.
PolicyExpiredErrorThe policy is past its expiresAt.
InsufficientFundsErrorThe wallet cannot cover the transaction plus fees.
RouteNotFoundErrorNo route exists within the allowlisted protocols and slippage.

Security model

  • Keys stay with the user. The SDK holds no private keys and transmits none. Signing is delegated to the user's wallet adapter.
  • Policies are signed. An agent's authority derives from a user signature, not from a config file you control.
  • Checks precede construction. Guardrails are enforced before a transaction is built, so a violation costs nothing and leaves no trace.
  • Revocation is unilateral. A user can end an agent's authority at any moment without your cooperation.
  • Least privilege by default. A new agent authorises nothing until a policy is attached.

FAQ

Is it really non-custodial? Yes. Keys stay on the user's device and never reach your servers or ours. An agent acts under a policy the user signed, not under a key we hold.

What happens if an agent exceeds its policy? The call is refused before a transaction is built. Nothing reaches the chain and no fee is paid.

Which chains are supported? Solana at launch. The policy model and agent interface are chain-agnostic by design; additional chains follow the public release.

Do I need to run a backend? No. The SDK runs client-side against the user's wallet. A backend is only needed if you want to orchestrate agents server-side, which requires a separate delegated-signing setup.

When does the beta open? We onboard in batches from the early-access list. Join it and we'll send your private npm tag and the docs when your batch opens.


Support


License

Copyright (c) 2025 Gamandeep. Released under the MIT License.

Ready to try it?

Install SOLAI Wallet from the Chrome Web Store

Install free