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

# Supervised user wallet

> A manager administers the account while the end user signs day to day, with signer-layer deny rules as guardrails.

<Note>
  Business Accounts are in **early access**. See the [overview](/docs/business-accounts/overview) for the model.
</Note>

An end user owns their day-to-day signing, but a manager administers the account and sets boundaries on what the user's signer can do. This fits wallets a platform operates on a customer's behalf, such as supervised employee spending wallets or family accounts where one party sets the limits.

## What you set up

A business account with one wallet, a manager who administers as an `admin` member, and one end-user signer bound by signer-layer deny rules.

Prerequisites: Business Accounts access, which is in early access, and [step-up authentication](/docs/javascript/reference/business-accounts/step-up-auth) for the caller who adds signers.

| Piece | Configuration |
| - | - |
| Members | Manager as `admin`; the end user needs no member role to sign |
| Signers | The end user, added with `signerType: 'endUser'` |
| Signer-layer policy | `denyAddresses` (and optionally `blockExport`) scoped to the user's share set |

<Steps>
  <Step title="Create the account and wallet">
    The manager signs up, creates the business account, and creates the wallet the end user will sign with. As creator, the manager becomes the owner and the wallet's first signer. That first signer matters later, because only someone already signing on a wallet can add new signers to it.

    ```javascript theme={"system"}
    import {
      createBusinessAccount,
      createWalletForBusinessAccount,
    } from '@dynamic-labs-sdk/client/waas';

    const account = await createBusinessAccount({ name: 'Guarded Wallet' });
    const businessAccountId = account.id;

    const walletAccount = await createWalletForBusinessAccount({
      businessAccountId,
      chain: 'EVM',
    });
    ```
  </Step>

  <Step title="Add the manager as admin">
    The account's creator is already the owner, so this step applies when a different operator administers the account. The manager administers but does not need to sign beyond the initial setup.

    ```javascript theme={"system"}
    import { addBusinessAccountMember } from '@dynamic-labs-sdk/client/waas';

    await addBusinessAccountMember({
      businessAccountId,
      targetIdentity: { identifier: 'manager@provider.com', identifierType: 'email' },
      role: 'admin',
    });
    ```
  </Step>

  <Step title="Add the end user as signer">
    Adding a signer requires [step-up authentication](/docs/javascript/reference/business-accounts/step-up-auth) and a caller who is already an active signer on the wallet; the creator qualifies from the previous step. Best practice also puts governance on `addSignerToWallet` so signer additions need approvals; see [Governance](/docs/business-accounts/governance).

    ```javascript theme={"system"}
    import {
      addBusinessAccountSigner,
      isBusinessAccountActionRequired,
    } from '@dynamic-labs-sdk/client/waas';

    const result = await addBusinessAccountSigner({
      businessAccountId,
      walletAccount,
      signerType: 'endUser',
      targetIdentity: { identifier: 'user@example.com', identifierType: 'email' },
    });

    if (isBusinessAccountActionRequired(result)) {
      throw new Error('Adding this signer requires approval.');
    }

    const { shareSetId } = result;
    ```
  </Step>

  <Step title="Set signer-layer deny rules">
    Scope `createPolicy` to the end user's share set so the deny list applies only to their signing, not to the manager's administration or any other signer. Deny known-bad or off-limits destinations; add `blockExport` to keep the key from leaving the wallet.

    ```javascript theme={"system"}
    import { createPolicy } from '@dynamic-labs-sdk/client/waas';
    import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';

    await createPolicy({
      scope: { walletId: walletAccount.verifiedCredentialId, shareSetId },
      chain: WaasChainEnum.Evm,
      chainIds: [1],
      rules: {
        denyAddresses: ['0x...'],
        blockExport: true,
        names: { denyAddresses: 'Blocked destinations' },
      },
    });
    ```

    Because rules must pass every layer, the manager can also set broader account or wallet rules underneath. See [Policies](/docs/javascript/reference/business-accounts/policies/overview).
  </Step>
</Steps>

## Things to know

* A `shareSetId` rotates when wallet shares refresh. Re-read it before each policy update rather than storing it; a stale value is rejected with a stale-share-set error. See [Policies](/docs/javascript/reference/business-accounts/policies/overview#signer-layer).
* You cannot remove the last active signer on a wallet. Add a replacement signer before removing the current one.
* Members and signers are independent: the manager signs here only because they created the wallet, not because `admin` grants signing, and the end user's signer access grants no admin rights.


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