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

# Integrate the SDK

> Wire @altheia-xyz/sui into your agent: derive refs from the key, act, handle denials.

The SDK builds the policy-gated transactions; the Move contract enforces the policy. Your agent process holds a private key and calls `AltheiaSui` methods. The contract decides whether each action lands.

## Install

```bash theme={null}
npm i @altheia-xyz/sui
```

Node 20+. `@altheia-xyz/sui` re-exports the `@mysten/sui` primitives an agent needs (`SuiJsonRpcClient`, `getJsonRpcFullnodeUrl`, `Ed25519Keypair`, `decodeSuiPrivateKey`), so there is one copy of `@mysten/sui` in play. A dapp-kit executor is provided for browser wallet flows.

## Env

The agent needs only its key, from provisioning:

```bash theme={null}
AGENT_PRIVKEY=suiprivkey1...
```

## Construct the agent

`agentRefs` reads the `AgentCap` the key owns and derives the vault, policy, and cap. `keypairExecutor` signs and submits, waiting for finality so sequential actions don't race.

```ts theme={null}
import {
  SuiJsonRpcClient, getJsonRpcFullnodeUrl, Ed25519Keypair, decodeSuiPrivateKey,
  AltheiaSui, keypairExecutor, agentRefs,
} from "@altheia-xyz/sui";

const client = new SuiJsonRpcClient({ url: getJsonRpcFullnodeUrl("testnet"), network: "testnet" });
const kp = Ed25519Keypair.fromSecretKey(decodeSuiPrivateKey(process.env.AGENT_PRIVKEY!).secretKey);

const refs = await agentRefs(client, kp.getPublicKey().toSuiAddress());
const agent = new AltheiaSui(client, refs, keypairExecutor(client, kp));
```

`agentRefs` throws if the address owns no `AgentCap` — wrong key, or the agent is not provisioned.

## Act

```ts theme={null}
const r = await agent.swap(50_000_000n);   // 0.05 SUI, gated by the policy
console.log("landed", r.digest);
```

`swap` buys (spends the capped quote, receives base into the vault). `sellSwap` unwinds a base position back to quote. Amounts are base units. Each method builds, signs, and submits internally.

## Handle denials

A policy denial surfaces as a thrown error. `decodePolicyAbort` tells a policy denial apart from a liquidity or gas failure.

```ts theme={null}
import { decodePolicyAbort } from "@altheia-xyz/sui";

try {
  await agent.swap(2_000_000_000n);     // over the per-tx cap
} catch (e) {
  const ab = decodePolicyAbort(e);
  if (ab) handleDenied(ab.reason_code); // "over_per_tx_cap" | "policy_revoked" | ...
  else throw e;                         // not a policy decision — surface it
}
```

Denials are normal control flow. A capped agent will hit them.

## Record denials without spending gas

A denied action aborts on-chain and emits no event, so to log denials, dry-run first. `guardedSubmit` dry-runs, records a policy abort to the audit backend, and submits only when allowed.

```ts theme={null}
import { buildSwap, guardedSubmit } from "@altheia-xyz/sui";

const r = await guardedSubmit(
  client, keypairExecutor(client, kp), kp.getPublicKey().toSuiAddress(),
  buildSwap(refs, 50_000_000n),
  { baseUrl, token, agent_id, action_type: "deepbook_swap", amount: 0.05, asset: "SUI" },
);
// r.ok ? r.digest : r.reason_code
```

## Read state

```ts theme={null}
const p = await agent.policy();        // live caps + state from chain
const log = await agent.auditLog(10);  // recent on-chain events
```

Or read directly with `readPolicyObject`, `vaultBalances`, `readAuditLog`. See the [SDK reference](/sdk/reads).

<Card title="Runnable example" icon="play" href="/guides/deepbook-swap-example" horizontal>
  A DeepBook agent: allowed, denied, revoked.
</Card>
