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

# Members & Roles

> Administer who can manage a business account, and transfer ownership.

> [!NOTE]
>
> Business Accounts are in **early access**. See [Business Accounts](https://docs.dynamic.xyz/docs/business-accounts/accounts.md) for the model.

Members control who can administer the account. That is separate from [who can sign](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/manage-signers.md). There are three roles:

| Role | Can do |
| - | - |
| `owner` | Everything, including transferring ownership. Exactly one per account. |
| `admin` | Add/remove members and signers, link wallets. |
| `viewer` | Read-only access. |

An account can also define [custom roles](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/custom-roles.md) that inherit `admin` or `viewer`, so a member holds a name your product recognizes (`cfo`, `treasurer`) instead of a generic built-in.

> [!NOTE]
>
> Adding someone as a **member** does not let them sign, and adding a **signer** does not grant admin rights. When a signer becomes active, they are added as a `viewer` member if they are not already a member. Member and role operations require [step-up authentication](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/step-up-auth.md).

An account can also define custom roles with `defineBusinessAccountRole`, each inheriting a built-in role. A member's `role` always reports the built-in they hold; a held custom role appears separately on `member.customRole` as `{ name, inherits }`, and it is `null` for a member holding a built-in role directly.

```javascript theme={"system"}
const member = detail.members.find(({ userId }) => userId === targetUserId);
console.log(member.role, member.customRole?.name); // 'admin' 'cfo'
```

## Who can call what

Every call acts on behalf of the signed-in user. Reads require membership, and modifications such as adding members or signers, linking wallets, and transferring ownership require the owner or admin role. A call made without the required role fails, so check `detail.members` for the caller's role before you show those actions in your UI.

## Add a member

`addBusinessAccountMember` adds a member with a built-in role (`admin` or `viewer`, defaults to `viewer`) or a [custom role](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/custom-roles.md) the account has defined. Identify them with a `targetIdentity`: a known `userId`, or an `identifier` + `identifierType` (the user is created if absent).

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { addBusinessAccountMember } from '@dynamic-labs-sdk/client/waas';
>
> await addBusinessAccountMember({
>   businessAccountId: account.id,
>   targetIdentity: { identifier: 'admin@acme.com', identifierType: 'email' },
>   role: 'admin',
> });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useAddBusinessAccountMember } from '@dynamic-labs-sdk/react-hooks';
>
> const { mutate } = useAddBusinessAccountMember();
> mutate({ businessAccountId, targetIdentity: { userId: 'user-123' }, role: 'viewer' });
> ```

An account holds up to 10 members by default, and the owner counts as one. See [Limits](https://docs.dynamic.xyz/docs/business-accounts/accounts.md#limits) for the configurable caps. When the account is full, the call throws an `APIError` with `status` 422 and the message "Business account has reached the maximum number of members". Its `code` is `unknown_error`, so match on the `status`.

Adding someone who is already a member succeeds, even at the limit, and returns the existing member unchanged. The `role` you pass is ignored, so use `updateBusinessAccountMemberRole` to change a role.

Adds sent at the same moment can fail with a 409 that asks you to retry. Retrying is safe.

## Change a member's role

`updateBusinessAccountMemberRole` changes a member's role to `admin`, `viewer`, or a [custom role](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/custom-roles.md) the account has defined, including moving between two custom roles. Use ownership transfer, below, to change who the owner is.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { updateBusinessAccountMemberRole } from '@dynamic-labs-sdk/client/waas';
>
> await updateBusinessAccountMemberRole({
>   businessAccountId: account.id,
>   userId,
>   role: 'admin',
> });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useUpdateBusinessAccountMemberRole } from '@dynamic-labs-sdk/react-hooks';
>
> const { mutate } = useUpdateBusinessAccountMemberRole();
> mutate({ businessAccountId, userId, role: 'viewer' });
> ```

## Remove a member

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { removeBusinessAccountMember } from '@dynamic-labs-sdk/client/waas';
>
> await removeBusinessAccountMember({ businessAccountId: account.id, userId });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useRemoveBusinessAccountMember } from '@dynamic-labs-sdk/react-hooks';
>
> const { mutate } = useRemoveBusinessAccountMember();
> mutate({ businessAccountId, userId });
> ```

> [!TIP]
>
> Removing a member also tears down any [signer](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/manage-signers.md) rows they held on the account's wallets. They lose signing access too, not just admin rights.

## Transfer ownership

`transferBusinessAccountOwnership` promotes an existing member to owner and atomically demotes the current owner to `admin`. Owner-only.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { transferBusinessAccountOwnership } from '@dynamic-labs-sdk/client/waas';
>
> await transferBusinessAccountOwnership({
>   businessAccountId: account.id,
>   newOwnerUserId,
> });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useTransferBusinessAccountOwnership } from '@dynamic-labs-sdk/react-hooks';
>
> const { mutate } = useTransferBusinessAccountOwnership();
> mutate({ businessAccountId, newOwnerUserId });
> ```

> [!WARNING]
>
> Transferring ownership revokes the caller's session server-side (their scope changed from owner to admin), so the current owner is signed out and must re-authenticate to pick up their new role. The new owner must already be a member.

## Next steps

> [card] [Custom roles](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/custom-roles.md)
>
> Define named roles that inherit `admin` or `viewer`.

> [card] [Governance](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/governance.md)
>
> Require approvals before a member or role change applies.


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