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

# Technical Reference

> Complete technical reference for the Zyfai SDK: architecture, configuration, types, and integration patterns.

One-stop technical reference for the **Zyfai SDK** (`@zyfai/sdk`). This page is the canonical map of how the SDK is wired, what it exposes, and how to plug it into a backend, a frontend, or an AI agent. For per-method signatures see the [Smart Wallet API](/docs/sdk/api/overview) and the [Intelligence Layer](/docs/sdk/intelligence-layer).

Create your own api key on the [SDK Dashboard](https://sma.zyf.ai)

## Architecture

The SDK is a thin TypeScript layer that bridges your app with **two backend surfaces** and an **on-chain Safe smart account stack**. Everything is exposed through a single class: `ZyfaiSDK`, organized into the [Smart Wallet API](/docs/sdk/api/overview) (execution) and the [Intelligence Layer](/docs/sdk/intelligence-layer) (read-only engine access).

```mermaid theme={null}
---
config:
  look: classic
  theme: neutral
---
flowchart LR
    App@{ shape: rounded, label: "Your app<br/>(Node.js, browser, AI agent)" }
    SDK@{ shape: rounded, label: "@zyfai/sdk<br/>ZyfaiSDK class" }
    Exec@{ shape: rounded, label: "Execution API<br/>/api/v1" }
    Data@{ shape: rounded, label: "Data API<br/>/api/v2" }
    Chain@{ shape: rounded, label: "Safe7579 + ERC-4337<br/>Base · Arbitrum · Ethereum" }
    App --> SDK
    SDK --> Exec
    SDK --> Data
    SDK --> Chain
```

| Backend | Swagger UI | API base | Responsibility |
| :- | :- | :- | :- |
| **Execution** | [api.zyf.ai/api-docs](https://api.zyf.ai/api-docs) | `https://api.zyf.ai/api/v1` | Deposits, withdrawals, transactions, session management, deposit registration |
| **DeFi data** | [defiapi.zyf.ai/api-docs](https://defiapi.zyf.ai/api-docs/) | `https://defiapi.zyf.ai/api/v2` | Earnings, opportunities, APY history, platform analytics |
| **On-chain** | — | — | Safe7579 smart accounts, ERC-4337 bundling, ERC-8004 identity |

OpenAPI tables and execution vs data routing: [API Reference Overview](/docs/sdk/api/overview).

## Installation

`@zyfai/sdk` is published on the public npm registry. `viem` is a required peer dependency.

**Latest version:**

<a href="https://www.npmjs.com/package/@zyfai/sdk">
  <img src="https://img.shields.io/npm/v/@zyfai/sdk" alt="npm" />
</a>

```bash theme={null}
# npm
npm install @zyfai/sdk viem

# pnpm
pnpm add @zyfai/sdk viem

# yarn
yarn add @zyfai/sdk viem
```

Requirements: **Node 18+** or any modern browser. Hold the API key on a server. An origin whitelist is only required when a browser calls Zyfai directly — see [API key and CORS](/docs/sdk/getting-started#api-key-and-cors).

## Configuration

### `SDKConfig`

```typescript theme={null}
interface SDKConfig {
  apiKey: string;
  rpcUrls?: Partial<Record<SupportedChainId, string>>;
}
```

| Field | Type | Required | Purpose |
| :- | :- | :- | :- |
| `apiKey` | `string` | Yes | Project key (`zyfai_...`). Get one at [sma.zyf.ai](https://sma.zyf.ai) or [programmatically](/docs/sdk/agent-quickstart#programmatic-api-key-creation-agent-native). |
| `rpcUrls` | `Partial<Record<SupportedChainId, string>>` | No | Custom RPC endpoints per chain (defaults to public RPCs). Override in production. |

### Supported chains

```typescript theme={null}
type SupportedChainId = 8453 | 42161 | 1;
```

Chains, assets, decimals, minimums, and strategies: [Supported Assets](/docs/sdk/supported-assets).

```typescript theme={null}
import { getSupportedChainIds, isSupportedChain } from "@zyfai/sdk";

getSupportedChainIds();       // [8453, 42161, 1]
isSupportedChain(8453);       // true
```

### Environment variables

```bash theme={null}
ZYFAI_API_KEY=zyfai_xxxxxxxxxxxxxxxx
PRIVATE_KEY=0x...                       # backend only

# Optional but recommended in production
BASE_RPC_URL=https://base-mainnet.g.alchemy.com/v2/...
ARBITRUM_RPC_URL=https://arb-mainnet.g.alchemy.com/v2/...
MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/...
```

## Integration Patterns

The SDK runs in three flavors. Pick the one that matches your runtime.

### Backend / Node.js (private key)

```typescript theme={null}
import { ZyfaiSDK } from "@zyfai/sdk";

const sdk = new ZyfaiSDK({
  apiKey: process.env.ZYFAI_API_KEY!,
  rpcUrls: {
    8453:  process.env.BASE_RPC_URL,
    42161: process.env.ARBITRUM_RPC_URL,
    1:     process.env.MAINNET_RPC_URL,
  },
});

await sdk.connectAccount(process.env.PRIVATE_KEY!, 42161);
```

### Frontend (EIP-1193 provider)

Works with any EIP-1193 provider: wagmi, Reown AppKit, `window.ethereum`, web3-react. The browser signs SIWE. Do not put the partner API key in the page: `NEXT_PUBLIC_` (or any client env var) inlines it into the bundle. In production the SDK that sends `X-API-Key` runs on your backend, and the browser only supplies the wallet provider. A browser that does call Zyfai directly also needs its page origin whitelisted. See [API key and CORS](/docs/sdk/getting-started#api-key-and-cors).

```typescript theme={null}
import { ZyfaiSDK } from "@zyfai/sdk";

// Do not use NEXT_PUBLIC_ZYFAI_API_KEY — that inlines the key into the bundle.
const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! });

await sdk.connectAccount(provider, 8453); // SIWE handshake is automatic
```

### Headless analytics (no wallet)

Some methods only need the API key. This is useful for B2B dashboards, monitoring, billing.

```typescript theme={null}
const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! });

const wallets = await sdk.getSdkAllowedWallets();
const tvl     = await sdk.getSdkKeyTVL();
```

## Standard Flow

For Smart Wallet integrations, every consumer goes through the same steps:

```text theme={null}
1. CONNECT   sdk.connectAccount(...)
2. SEND      sdk.sendDeposit(eoa, chainId, amountInWei, asset, strategy?)
3. CREDIT    sdk.waitForDepositCredit(depositId, chainId)
4. POSITION  sdk.waitForDepositPosition(depositId, chainId)   // optional UI wait
5. WITHDRAW  sdk.withdrawFunds(eoa, chainId, amountInWei?, asset?)
6. SETTLE    sdk.waitForWithdrawSettlement(withdrawalId, chainId)
7. COMPLETE  sdk.waitForWithdrawComplete(withdrawalId, chainId)  // when async
```

<Warning>
  The first `sendDeposit` call associates the EOA with a **pre-deployed Safe** that already has a **signed session key**, live on Base, Arbitrum, and Mainnet at once. No separate `deploySafe` / `createSessionKey` step is needed. This does not change the EOA itself.
</Warning>

Notes:

* Always pass the **EOA address** as `userAddress`, never the Safe address. The SDK resolves the backend-assigned Safe.
* First deposit makes the Safe available on **all three chains** immediately (not only the `chainId` you deposited on).
* [`sendDeposit`](/docs/sdk/api/send-deposit) returns after transfer confirmation and lifecycle registration. Follow it with [`waitForDepositCredit`](/docs/sdk/api/wait-for-deposit-credit) when the UI needs credited balance, and [`waitForDepositPosition`](/docs/sdk/api/wait-for-deposit-position) when it should wait for allocation.
* Withdrawals are processed **asynchronously** — poll `withdrawFunds().lifecycle.id` with [`waitForWithdrawSettlement`](/docs/sdk/api/wait-for-withdraw-settlement) and [`waitForWithdrawComplete`](/docs/sdk/api/wait-for-withdraw-complete). Do not call `withdrawFunds` again for the same request.

## Strategies

`sendDeposit` (first deposit) and `updateUserProfile` accept a strategy that drives the Intelligence Engine's risk profile.

Each tier is a superset of the previous one: an aggressive user also gets
conservative pools, and a yieldmaxxing user gets everything.

| Strategy | Backend value | Risk profile | Default |
| :- | :- | :- | :- |
| `"conservative"` | `safe_strategy` | Low-risk, stable yield | yes |
| `"aggressive"` | `degen_strategy` | Higher yield, higher risk | no |
| `"yieldmaxxing"` | `async_strategy` | Aggressive + pools with delayed withdrawals | no |

```typescript theme={null}
const sent = await sdk.sendDeposit(eoa, 8453, "100000000", "USDC", "conservative");
await sdk.waitForDepositCredit(sent.registration.id, 8453);
await sdk.updateUserProfile({ strategy: "aggressive" });
```

`"yieldmaxxing"` is the only strategy that changes how withdrawals behave. It
unlocks protocols (Ipor, Superform) that cannot be exited on demand: a
redemption is requested, then claimed once the protocol releases the funds (roughly a day on Ipor, three on Superform). The agent handles both steps, but
the funds are in flight in between and are **missing from every balance
field**. Only one redemption can be in flight per pool: a second
`withdrawFunds` on that pool throws until the entry reaches `CLAIMED`. See
[withdrawFunds](/docs/sdk/api/withdraw-funds) and
[getPortfolio](/docs/sdk/api/get-portfolio).

## Session Keys

Session keys are assigned with the pre-deployed Safe on first deposit. They allow Zyfai's Intelligence Engine to rebalance on the user's behalf within strict, enforced limits.

What a session key **can** do:

* Move funds **between approved pools** on the same Safe
* Trigger auto-compounding
* Execute capital splitting across pools

What a session key **cannot** do:

* Withdraw to any external address
* Interact with contracts outside the curator-managed registry
* Sign arbitrary calldata (every transaction is byte-validated by the Security Proxy Gateway)

See the [Session Keys product page](/docs/product/control/session-keys) and [Security Proxy Gateway](/docs/product/control/proxy) for the full enforcement model.

## Amount formatting

Token amounts for deposits and withdrawals use **least decimal units** (wei-style):

```typescript theme={null}
// For USDC / EURC (6 decimals), 100 = 100 * 10^6
const sent = await sdk.sendDeposit(eoa, 8453, "100000000", "USDC");
await sdk.waitForDepositCredit(sent.registration.id, 8453);
```

Earnings values (`totalEarningsByToken`, `totalEarningsByChain`, `daily_total_delta_by_token`) are returned as **decimal strings** (e.g. `"421.315354"`). Parse them with `parseFloat()` when doing arithmetic.

## AI-Agent Integration

The SDK is designed to be operated **by an autonomous agent**, not just a human-driven app.

* **Programmatic API key creation**: agents can mint their own SDK key linked to their wallet, no human in the loop. See [Agent Quickstart → Programmatic API Key Creation](/docs/sdk/agent-quickstart#programmatic-api-key-creation-agent-native).
* **ERC-8004 identity**: register the agent on-chain in the Identity Registry via `registerAgentOnIdentityRegistry`.
* **Compact single-page reference**: the SDK surface for agents is [Agent Quickstart](/docs/sdk/agent-quickstart) ([raw markdown](https://docs.zyf.ai/docs/sdk/agent-quickstart.md)). Chat clients connect through [zyf.ai/skill.md](https://zyf.ai/skill.md).

## Type Safety

The SDK ships full TypeScript typings. Import types as needed:

```typescript theme={null}
import type {
  SDKConfig,
  SupportedChainId,
  DepositResponse,
  PositionsResponse,
  UpdateUserProfileResponse,
  OnchainEarningsResponse,
  SimulateBestPositionsResponse,
} from "@zyfai/sdk";
```

## Response Format

All SDK methods return consistent response objects:

```typescript theme={null}
{
  success: boolean;
  // ...method-specific fields
}
```

## Error Handling

### Strategy

* API errors are returned as response objects with `error` / `message` fields when recoverable
* Network failures and 5xx responses are surfaced as thrown `Error` instances and retried with exponential backoff
* On-chain errors bubble up from the underlying signer (viem / wallet provider). User rejections appear as standard provider errors.
* `401` responses trigger automatic re-authentication; persistent failure throws

### Pattern

```typescript theme={null}
try {
  const sent = await sdk.sendDeposit(userAddress, chainId, amount, "USDC");
  await sdk.waitForDepositCredit(sent.registration.id, chainId);
} catch (error) {
  const message = error instanceof Error ? error.message : String(error);

  if (message.includes("Safe not available")) return "Safe not assigned yet. Retry deposit.";
  if (message.includes("User rejected"))    return "Signing was rejected.";
  if (message.includes("No account"))       return "Call sdk.connectAccount() first.";
  if (message.includes("Unsupported chain")) return "Chain must be 8453, 42161 or 1.";

  throw error;
}
```

### Common errors

| Message | Cause |
| :- | :- |
| `No account connected` | `connectAccount()` not called or has not resolved |
| `Unsupported chain` | `chainId` is not one of `8453`, `42161`, `1` |
| `Safe not available` | Safe not yet assigned / available for this EOA on chain |
| `User rejected request` | User declined the signature in their wallet |
| `401 Unauthorized` | API key invalid, expired, or wallet not whitelisted |

## Rate Limiting

API calls are rate-limited per project key. The SDK applies automatic retry with exponential backoff on transient failures (network, 5xx, 429).

## Reporting Issues

Include in every report:

* SDK version (`@zyfai/sdk`)
* Runtime (Node version, browser, framework)
* API key **prefix only** (e.g. `zyfai_361ad4...`), never the full key
* Error message and stack trace
* Minimal reproduction steps
* Expected vs actual behavior

Channels: [GitHub Issues](https://github.com/ondefy/zyfai-sdk/issues) · [Telegram](https://t.me/zkzyfi) · [zyf.ai](https://zyf.ai)


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