> ## Documentation Index
> Fetch the complete documentation index at: https://sdk-guide.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Organization Wallets

> Org-owned wallets, portfolios, UTXOs, history, and the Corporate Address Book

## Overview

Org wallets are owned by the organization, created by a Master, and handed to employees through the assignment + provisioning handshake described on [Organization](https://sdk-guide.mintlify.site/sdk-guide/organization.md).

Two visibility rules run through every method on this page:

* A Master sees every wallet in the organization.
* An Employee sees only wallets currently assigned to them. Anything else is `403` or `404`.

## Wallet scope

`WalletScope` is `'personal' | 'organization'`. See [Wallet scope](https://sdk-guide.mintlify.site/sdk-guide/wallets.md#wallet-scope) on Wallets for what it is and which methods accept it. Passing `'organization'` switches share fetches, share rotation, spend authorization, vault lifecycle and orders to their organization equivalents in one step.

`walletScope` is an optional field on `SendTransactionInput`, `SendTokenInput`, `EstimateFeeInput`, `ExportWalletInput`, `CreateMultisigInput`, `ActivateMultisigInput`, `CreateOrderInput`, `CreateSendOrderInput`, `CreateSettingsOrderInput`, `SignOrderInput`, `RejectOrderInput`, `ExecuteOrderInput`, `GetOrdersInput`, `GetOrderByIdInput`, and `DeleteOrderInput`.

```typescript theme={null}
const userRef = await sdk.getSdkUserId();
await sdk.unlockWalletSession(userRef, password);

await sdk.sendTransaction({
  walletScope: 'organization',
  chain: EChainType.EVM,
  from: orgWalletAddress,
  to: recipient,
  amount: '1.0',
  chainId: 1,
  tokenAddress: '',
  decimals: 18,
  isNativeToken: true,
  userRef,
});
```

> [!NOTE]
>
> When `walletScope` is omitted, the share fetch tries the personal path first and retries on the org path on `404` or `403`. Passing `walletScope: 'organization'` skips that wasted round trip, so set it explicitly when you know the wallet is org-owned.

### Spend authorization

Every send hands the unsigned transaction to the server before the key is rebuilt. The server reads the real recipient, token and amount out of it and returns a single-use `authorizationId`:

```typescript theme={null}
type SpendAuthorizationResponse = {
  authorizationId: string;
  expiresAt?: string;
  recipient?: string;
  tokenSymbol?: string;
  amountHuman?: number;
};
```

That handle is then sent as `spendAuthorizationId` on the share request, and the server charges the org's daily spending limit against its own reading of the transaction rather than a client-reported amount. The two are mutually exclusive: the SDK never sends `spendAuthorizationId` together with a client-computed `spendAmountHuman`.

This is fully automatic inside `sendTransaction`; there is no public SDK method for it. When the server replies `400` with body code `ERROR_SPEND_NOT_DECODABLE`, the SDK falls back to the client-computed context rather than blocking the send. The authorization step also runs the `forceAddressBook` destination check. See [Governance & policies](https://sdk-guide.mintlify.site/sdk-guide/organization-policies.md).

## Creating and managing org wallets

```typescript theme={null}
const userRef = await sdk.getSdkUserId();
await sdk.unlockWalletSession(userRef, password);

const { wallets } = await sdk.createOrgWallet({
  chain: EChainType.EVM,
  userRef,
  password,
  mode: 'generate', // 'generate' | 'ecdh'; resolved from the account profile when omitted
});

await sdk.renameOrgWallet({
  chainType: EChainType.EVM,
  address: wallets[0].address,
  name: 'Payroll',
});

const wallet = await sdk.getOrgWallet({ walletAddress: wallets[0].address });

await sdk.deleteOrgWallet({
  chainType: EChainType.EVM,
  address: wallets[0].address,
});
```

`createOrgWallet` runs the same client-side MPC generation as the personal `createWallet` and then registers the wallet with the backend; the device share is written to `shareStore` before the method resolves. When `mode` is omitted the SDK resolves it from the account profile: an account with a recovery phrase takes the shareless `seed` path, and the resulting `OrgWalletItem` carries `derivationSource: 'seed'` with an `index`. Those fields, with `derivationSeedId` when the listing has it, are exactly what `provisionOrgMemberWalletAccess` needs later.

### Which phrase a seed wallet comes from

A `seed` org wallet derives from the organization's own [recovery phrase](https://sdk-guide.mintlify.site/sdk-guide/recovery-phrase.md#organization-recovery-phrase), or from the Master's personal phrase while the organization is linked to it. The SDK reads which one applies; pass `seedOwnerKind: 'organization' | 'personal'` only to pick it yourself.

When the organization uses a phrase of its own, that phrase has to exist and be confirmed first:

| Organization state | `createOrgWallet` throws |
| :- | :- |
| No phrase yet | `OrgRecoveryPhraseRequiredError` |
| No phrase yet, and the Master still has to choose between linking and a new phrase | `OrgSeedChoiceRequiredError` |
| Phrase created but not confirmed | `OrgRecoveryPhraseUnverifiedError` |
| Phrase locked until it is entered again in the web app | `SeedAwaitingPhraseError` |

`deleteOrgWallet` triggers server-side MPC share cleanup and writes an `Org Wallet Deleted` audit row.

## Listing

```typescript theme={null}
interface OrgWalletItem {
  id: string;
  address: string;
  chainType: string;              // lowercased server key, e.g. "evm"
  name: string;
  isImported: boolean;
  cryptoAccessStatus?: 'none' | 'pending' | 'accepted';
  shareVersion?: number;
  derivationSource?: 'legacy' | 'seed';
  index?: number | null;
  accessState?: 'active' | 'archived' | 'access_lost';
  derivationSeedId?: string;                     // the phrase a seed wallet derives from
  seedOwnerKind?: 'personal' | 'organization';   // whose phrase that is
}

interface OrgWalletsResponse {
  wallets: OrgWalletItem[];
  total?: number;   // paginated requests only
  page?: number;    // paginated requests only
  limit?: number;   // paginated requests only
}

interface OrgMyWalletsResponse {
  wallets: OrgWalletItem[];
}
```

```typescript theme={null}
// Master: every org wallet available for assignment
const all = await sdk.listOrgWallets();

// Opt-in pagination + chain filter
const page = await sdk.listOrgWallets({
  page: 1,
  limit: 20,
  chainTypes: [EChainType.EVM, EChainType.SOL],
});

// Master or Employee: wallets assigned to the calling key
const { wallets } = await sdk.listMyOrgWallets();
```

> [!WARNING]
>
> Pagination on `listOrgWallets` is opt-in. Omit `page` and `limit` and you get the full list with no `total`, `page` or `limit` fields, so do not branch on `total` being present to decide whether more pages exist. `limit` is capped at 100. `chainTypes` filters in both modes.

## Balances, UTXOs, history

```typescript theme={null}
const { totalAssetValueUSD } = await sdk.getOrgTotalAssetValue();

const portfolios = await sdk.getOrgWalletsPortfolio(
  [{ walletAddress, chainType: EChainType.EVM, chain: '1' }],
  { force: true },
);

const one = await sdk.getOrgWalletPortfolio({
  walletAddress,
  chainType: EChainType.EVM,
  chain: '1',
  force: false,
});

const { utxos } = await sdk.getOrgWalletUtxos({
  walletAddress: btcAddress,
  chainType: EChainType.BTC,
  chain: 'BTC',
});

const history = await sdk.getOrgWalletHistory({
  walletAddress,
  chainType: EChainType.EVM,
  page: 1,
  limit: 20,
  hideDust: true,
});
```

> [!NOTE]
>
> `getOrgWalletPortfolio` is the one-wallet form of the batch method. The batch form settles each wallet independently and silently drops failures, so an inaccessible wallet comes back as an empty array, which the SDK turns into a `NotFoundError` rather than `undefined`.
>
> An Employee without `ViewBalances` still gets a response from the batch form, but every entry has `tokens: []`.

`OrgWalletUtxosResponse` is `{ utxos: unknown[] }`. Entries are chain-specific, since BTC and ADA differ, so cast at the call site based on `chainType`.

## Lower-level building blocks

`provisionOrgMemberWalletAccess` and `acceptOrgWalletAccessWithPassword`, described under [Employee wallet provisioning](https://sdk-guide.mintlify.site/sdk-guide/organization.md#employee-wallet-provisioning) on Organization, are convenience wrappers. Split them when the crypto and the HTTP call must happen in different processes:

```typescript theme={null}
const built = await sdk.buildProvisionEmployeeWalletPayload(masterUserRef, {
  walletId,
  address,
  chainType: EChainType.EVM,
  memberId,
  tempPassword,        // optional, generated when omitted
  masterPassword,
  derivationSource,
  index,
  derivationSeedId,
});
// built.tempPassword, built.shares.{serverShareCiphertext,serverShareIv,
//                                   recoveryShareCiphertext,recoveryShareIv}

const accept = await sdk.buildAcceptEmployeeWalletPayload(employeeUserRef, {
  walletId,
  address,
  chainType: EChainType.EVM,
  memberId,
  tempPassword,
  ownPassword,
  passwordHint,
  createEncTokenIfMissing: true,
});
// accept.acceptBody (POST body), accept.deviceShareHex

await sdk.saveOrgWalletDeviceShare(employeeUserRef, {
  walletId,
  address,
  chainType: EChainType.EVM,
  deviceShareHex: accept.deviceShareHex,
  version,             // from the accept response
});
```

> [!NOTE]
>
> `buildProvisionEmployeeWalletPayload` does not call the server; it only produces the encrypted material. `buildAcceptEmployeeWalletPayload` does read what the Master handed over, but it does not post the accept. You own both HTTP calls in this mode.

## Corporate Address Book

The org address book is a separate store from the personal one documented in [Address Book](https://sdk-guide.mintlify.site/sdk-guide/address-book.md), and it is what the `forceAddressBook` policy whitelists against.

```typescript theme={null}
type OrgAddressRecipientType = 'individual' | 'corporate';
type OrgAddressWalletType = 'self_hosted' | 'crypto_service_provider';

interface OrgAddressBookEntry {
  id: string;
  name: string;
  address: string;
  chainType: ChainType;
  type: 'CEX' | 'Wallet';
  memo?: string | null;
  recipientType?: OrgAddressRecipientType;
  walletType?: OrgAddressWalletType;
  beneficiaryName?: string | null;
  registeredName?: string | null;
  vaspName?: string | null;
  vaspLei?: string | null;
  isVerified: boolean;
  createdAt: string;
  updatedAt: string;
}
```

```typescript theme={null}
const entries = await sdk.listOrgAddresses();      // all members
const verified = entries.filter((e) => e.isVerified);

const added = await sdk.addOrgAddress({
  address: '0x...',
  chainType: EChainType.EVM,
  name: 'Acme Ltd treasury',
  type: 'Wallet',
  recipientType: 'corporate',
  walletType: 'self_hosted',
  registeredName: 'Acme Limited',
  memo: 'Q3 settlements',
});
// AddOrgAddressResponse: { id: string; address: string; isVerified: boolean }

const updated = await sdk.updateOrgAddress({
  addressId: added.id,
  name: 'Acme Ltd treasury (EU)',
  memo: 'Q4 settlements',
});

await sdk.deleteOrgAddress({ addressId: added.id });
```

FATF Travel Rule fields are validated server-side and conditionally required:

| Condition | Required field |
| - | - |
| `recipientType === 'individual'` | `beneficiaryName` |
| `recipientType === 'corporate'` | `registeredName` |
| `walletType === 'crypto_service_provider'` | `vaspName` |

> [!NOTE]
>
> API-key adds are auto-verified. An entry created through an API key comes back with `isVerified: true` and immediately counts toward the `forceAddressBook` whitelist. Browser flows still require OTP confirmation, which is why `listOrgAddresses()` can return unverified rows. Only `isVerified === true` entries whitelist a transfer.

`UpdateOrgAddressInput` deliberately omits `address` and `chainType`: both are immutable server-side. `UpdateOrgAddressBookEntryInput` is that shape plus the `addressId` the SDK lifts into the path.

## Method reference

| SDK method | Role | API-key permission (any of) |
| - | - | - |
| `createOrgWallet` | Master | `WalletManagement` |
| `listOrgWallets` | Master | `WalletManagement` |
| `listMyOrgWallets` | Master, Employee | `ViewBalances`, `WalletManagement`, `VaultManagement`, `TransactionManagement` |
| `getOrgWallet` | Master, Employee | `ViewBalances`, `WalletManagement` |
| `renameOrgWallet` | Master | `WalletManagement` |
| `deleteOrgWallet` | Master | `WalletManagement` |
| `getOrgTotalAssetValue` | Master, Employee | `ViewBalances` |
| `getOrgWalletsPortfolio` / `getOrgWalletPortfolio` | Master, Employee | `ViewBalances`, `WalletManagement`, `VaultManagement`, `TransactionManagement` |
| `getOrgWalletUtxos` | Master, Employee | `ViewBalances` |
| `getOrgWalletHistory` | Master, Employee | `ViewTransactionHistory`, `WalletManagement`, `TransactionManagement` |
| `listOrgAddresses` | Master, Employee | `ViewBalances`, `WalletManagement`, `VaultManagement`, `TransactionManagement` |
| `addOrgAddress` | Master | `AddressBookManagement` |
| `updateOrgAddress` | Master | `AddressBookManagement` |
| `deleteOrgAddress` | Master | `AddressBookManagement` |


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