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

# Operate accounts without Grid

> Replace each Grid and Smart Account API call with the Smart Account SDK

Once your accounts are signed by your own keys, your app talks to the Smart Account Program directly through `@sqds/smart-account-core`. Each Grid call has a direct replacement: your key signs, your fee payer pays, and no Squads server is involved.

## Overview

* **One dependency**: `@solana/kit` is the only peer dependency.
* **v1 transactions**: `send` builds Solana v1 transactions, sets compute limits by simulating, and confirms against the transaction's own expiry. It never resends.
* **You pay**: fees and rent come from the fee payer you pass. Grid's paymaster is gone.
* **Narrow by design**: it covers accounts, transfers, wrapped transactions, signer changes and spending-limit removal. Anything else is in [Not provided](#not-provided).

## Replace each call

**1. Install and set up**

```bash theme={null}
npm install @sqds/smart-account-core @solana/kit@^8.6.0
```

```typescript theme={null}
import {
  createSolanaRpc,
  decompileTransactionMessage,
  getBase64Encoder,
  getCompiledTransactionMessageDecoder,
  getTransactionDecoder,
} from '@solana/kit';
import {
  buildCreateAccount,
  buildRemoveSpendingLimit,
  buildSetSigners,
  buildTransfer,
  checkOutcome,
  deriveProgramConfig,
  deriveVault,
  fetchAccount,
  fetchBalances,
  fetchSpendingLimits,
  resolveCreatedAccount,
  send,
  wrapTransaction,
} from '@sqds/smart-account-core';
```

The SDK works from the account's settings address. While Grid is up, read it with `resolveSettingsAddress` from `@sqds/grid/migration`, and store it.

```typescript theme={null}
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const account = await fetchAccount(rpc, settings);
const vault = await deriveVault(settings, 0);
```

**2. Read accounts and balances**

**Before (Grid):**

```typescript theme={null}
const account = await gridClient.getAccount(accountAddress);
const balances = await gridClient.getAccountBalances(accountAddress);
```

**After (Smart Account SDK):**

```typescript theme={null}
const balances = await fetchBalances(rpc, vault);
const limits = await fetchSpendingLimits(rpc, settings);
```

> [!NOTE]
>
> **Raw amounts.** `fetchBalances` returns lamports and token amounts with their decimals, without token names or prices.

**3. Send transfers**

Replaces on-chain payment intents. `buildTransfer` sends SOL (`mint: 'SOL'`) or any SPL token, and can create the recipient's token account.

**After (Smart Account SDK):**

```typescript theme={null}
const transfer = await buildTransfer({
  account,
  vaultIndex: 0,
  signers: [newSigner],
  mint: usdcMint,
  to: recipient,
  amount: 1_500_000n,
  decimals: 6,
  createRecipientAta: true,
});
const sent = await send(rpc, { instructions: [transfer], feePayer: newSigner });
```

Check every `send` result. `unknown` means the outcome is not known yet: resolve it with `checkOutcome`, never by sending again.

```typescript theme={null}
if (sent.status === 'unknown') {
  const checked = await checkOutcome(rpc, sent.signature, sent.lastValidBlockHeight);
  console.log(checked);
} else if (sent.status === 'failed') {
  console.log(sent.error.customCode, sent.error.logs);
}
```

**4. Execute your own transactions**

Replaces `POST /accounts/{address}/transactions` and `/submit`. `wrapTransaction` takes the transaction you build today and has the vault execute it.

**Before (Grid):**

```typescript theme={null}
const prepared = await gridClient.prepareArbitraryTransaction(accountAddress, {
  transaction: base64Transaction,
});
await gridClient.signAndSend({
  sessionSecrets,
  session,
  transactionPayload: prepared.data,
  address: accountAddress,
});
```

**After (Smart Account SDK):**

```typescript theme={null}
const tx = getTransactionDecoder().decode(getBase64Encoder().encode(base64Transaction));
const message = decompileTransactionMessage(getCompiledTransactionMessageDecoder().decode(tx.messageBytes));
const wrapped = await wrapTransaction({ account, vaultIndex: 0, signers: [newSigner], message });
await send(rpc, { instructions: [wrapped.instruction], feePayer: newSigner });
```

**5. Change signers**

**Before (Grid):**

```typescript theme={null}
await gridClient.updateAccount(accountAddress, {
  signers: [{ address: newSigner.address, role: 'primary', permissions: ['CAN_INITIATE', 'CAN_VOTE', 'CAN_EXECUTE'] }],
  threshold: 1,
});
```

**After (Smart Account SDK):**

```typescript theme={null}
const setSigners = buildSetSigners({
  account,
  signers: [newSigner],
  rentPayer: newSigner,
  newSigners: [
    { key: newSigner.address, permissions: ['initiate', 'vote', 'execute'] },
    { key: secondSigner, permissions: ['initiate', 'vote', 'execute'] },
  ],
  newThreshold: 1,
});
await send(rpc, { instructions: [setSigners], feePayer: newSigner });
```

> [!WARNING]
>
> **Keep the threshold reachable.** The new signers must hold every permission between them and be able to meet the threshold, or the account locks.

**6. Remove spending limits**

**Before (Grid):**

```typescript theme={null}
await gridClient.deleteSpendingLimit(accountAddress, spendingLimitAddress);
```

**After (Smart Account SDK):**

```typescript theme={null}
const removeLimit = buildRemoveSpendingLimit({
  account,
  signers: [newSigner],
  rentPayer: newSigner,
  spendingLimit: spendingLimitAddress,
});
await send(rpc, { instructions: [removeLimit], feePayer: newSigner });
```

**7. Create accounts**

Account creation is open to any creator on-chain. The SDK adds 25 candidate addresses so creation succeeds even when others create accounts at the same time.

**After (Smart Account SDK):**

```typescript theme={null}
const programConfig = await fetchEncodedAccount(rpc, await deriveProgramConfig());
if (!programConfig.exists) throw new Error('ProgramConfig not found');
const created = await buildCreateAccount({
  programConfig: { data: programConfig.data },
  creator: newSigner,
  signers: [{ key: newSigner.address, permissions: ['initiate', 'vote', 'execute'] }],
  threshold: 1,
});
const createdTx = await send(rpc, { instructions: [created.instruction], feePayer: newSigner });
if (createdTx.status === 'confirmed') {
  const newSettings = await resolveCreatedAccount(rpc, createdTx.signature, created.candidates);
  console.log(newSettings, await deriveVault(newSettings, 0));
}
```

## Endpoint map

### Grid

| Endpoint | Replacement | Notes |
| - | - | - |
| `POST /api/grid/v1/accounts`, `POST /api/grid/v1/accounts/verify`, `POST /api/grid/v1/accounts:custom` | `buildCreateAccount` + `send` + `resolveCreatedAccount` | You pay rent and fees. Email OTP sign-up is replaced by your own auth. |
| `GET /api/grid/v1/accounts/{address}` | `fetchAccount` | Takes the settings address, not the vault. Read it with `resolveSettingsAddress` while Grid is up. |
| `GET /api/grid/v1/accounts/{address}/balances` | `fetchBalances` | Raw amounts; no token metadata or prices. |
| `PATCH /api/grid/v1/accounts/{address}` | `buildSetSigners` + `send` | |
| `POST /api/grid/v1/accounts/{address}/transactions`, `POST /api/grid/v1/accounts/{address}/submit` | `wrapTransaction` + `send` | Your key signs and your fee payer pays; Grid's paymaster is gone. |
| `POST /api/grid/v1/accounts/{address}/payment-intent` (on-chain transfers) | `buildTransfer` + `send` | Fiat rails are not replaced. |
| `DELETE /api/grid/v1/accounts/{address}/spending-limit/{spending_limit_address}` | `buildRemoveSpendingLimit` + `send` | |
| Spending limit create, update and use; standing orders | Not provided | Run your own scheduler with your own key. |
| Proposals | Not provided | The SDK executes synchronously, when the signing keys meet the threshold together. |
| Auth, sessions, passkeys, KYC, virtual accounts, compliance, trading | Not provided | Use your own providers. |

### Smart Account API

| Endpoint | Replacement | Notes |
| - | - | - |
| `POST /api/v1/smart-accounts` | `buildCreateAccount` + `send` + `resolveCreatedAccount` | You pay rent and fees. |
| `GET /api/v1/smart-accounts/{smart_account_address}` | `fetchAccount` | |
| `GET /api/v1/smart-accounts/{smart_account_address}/balances` | `fetchBalances` | |
| `PATCH /api/v1/smart-accounts/{smart_account_address}` | `buildSetSigners` + `send` | |
| `POST /api/v1/smart-accounts/{smart_account_address}/transactions` | `wrapTransaction` + `send` | |
| `GET /api/v1/smart-accounts/{smart_account_address}/spending-limits` | `fetchSpendingLimits` | |
| `DELETE /api/v1/smart-accounts/{smart_account_address}/spending-limits/{spending_limit_address}` | `buildRemoveSpendingLimit` + `send` | |
| Spending limit create, update and use | Not provided | |

## Not provided

Spending-limit creation and use, standing orders, proposals, authentication, sessions, passkeys, KYC, virtual accounts, compliance and trading have no SDK replacement. Use your own scheduler and providers.

> [!TIP]
>
> **Another language?** The program's [testing framework](https://github.com/Squads-Protocol/smart-account-program/tree/main/tests) shows every instruction the SDK builds.

## Next Steps

> [card] [Troubleshooting](https://developers.squads.so/grid/v1/migration/troubleshooting.md)
>
> Error codes and what to do

> [card] [Smart Account Program](https://github.com/Squads-Protocol/smart-account-program)
>
> Program source and tests


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