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

# 為授權使用者建立消費帳戶

> 在你的帳戶下建立一個消費帳戶，並將授權使用者指派為其擁有者。

消費帳戶一律建立在**呼叫者的帳戶上**——無法建立屬於他人帳戶的帳戶。你可以做的是先建立消費帳戶，然後將授權使用者紀錄為其**擁有者**，讓該帳戶有一位負責人。

與 [`createVirtualCard`](/features/create-virtual-card-for-authorized-user) 不同，`createUserCashBalance` 並**不會**接受 `authUserId`。擁有權是另一個獨立呼叫：使用 [`assignObjectOwner`](/api-reference/mutations/assign-object-owner) 並帶上 `objectType: SPEND_ACCOUNTS`。

<Note>
  **擁有權是中繼資料，不是存取權。**

  指派擁有者會紀錄誰對某個消費帳戶負責。本身並不會讓那個人獲得從該帳戶消費的能力。實際的有效存取權仍取決於該使用者在帳戶層級的角色（[`UACRoleType`](/api-reference/types/uacrole-type)）與對該消費帳戶所授與的任何項目層級存取權兩者取其高。

  指派擁有者**同時**請確保該使用者的角色能提供你實際想要的存取權。
</Note>

***

## 先決條件

<Steps>
  <Step title="授權使用者已存在且為 ACTIVE">
    使用 [`addAuthorizedUser`](/features/create-authorized-users) 新增，並確認回傳的 `status` 為 `ACTIVE`。`PENDING` 的指派無法作為擁有者——使用者必須先接受邀請。
  </Step>

  <Step title="你的權杖同時具備兩個 scope">
    `createUserCashBalance` 需要 `MANAGE_PAYMENT`。`assignObjectOwner` 需要 `MANAGE_SUBUSERS`。單一 Bearer 權杖必須同時具備兩者，才能完整執行此流程。
  </Step>

  <Step title="你已取得該授權使用者的 userId">
    `assignObjectOwner` 以 `userId` 為鍵，而不是 `authUserId`。請見下方[解析 userId](#resolving-the-userid)。
  </Step>
</Steps>

***

## 步驟 1 — 建立消費帳戶

如同一般流程建立消費帳戶。它會在呼叫者的帳戶下建立，且未附帶擁有者。

```graphql theme={null}
mutation CreateUserCashBalance($input: CreateUserCashBalanceInput!) {
  createUserCashBalance(input: $input) {
    userCashBalanceId
    nickname
    availableCashBalance
    status
    createdAt
  }
}
```

```json theme={null}
{
  "input": {
    "nickname": "Ada — Field Ops"
  }
}
```

請保存回傳的 `userCashBalanceId`。此值會在步驟 3 作為 `objectId` 使用。

<Info>
  為帳戶設定能識別擁有者的暱稱。擁有權中繼資料不一定會在每個清單檢視中顯示，因此像是 `"Ada — Field Ops"` 這樣的暱稱，可讓帳戶在不需額外查詢的情況下，於 [`getUserCashBalances`](/features/get-spend-accounts) 中更容易辨識。
</Info>

***

## 解析 userId

`assignObjectOwner` 接受授權使用者的\*\*`userId`\*\*——即底層的使用者紀錄。這與 `addAuthorizedUser` 與 [`authorizedUsers`](/features/query-authorized-user) 回傳的 **`authUserId`** 不同，後者識別的是 UAC 的角色指派。

`AuthorizedUser` 型別目前尚未對外提供 `userId`。目前有紀錄的方法如下：

| 來源                                                                       | 取得方式                                                |
| :----------------------------------------------------------------------- | :-------------------------------------------------- |
| [`createVirtualCard`](/features/create-virtual-card-for-authorized-user) | 以 `authUserId` 呼叫時，回應中的 `userId` 即為該授權使用者的 user ID。 |
| [`registerUser`](/user-registration)                                     | 若你的平台曾註冊該使用者，請在註冊時保存該 user ID，並與你方對該人的紀錄關聯存放。       |

<Warning>
  請勿在需要 `userId` 的地方傳入 `authUserId`。兩者皆為 `UUID`，此 mutation 不會將此替換視為型別錯誤——你將得到失敗或誤導向的擁有權指派結果。
</Warning>

***

## 步驟 2 — 將授權使用者指派為擁有者

<Card title="受限存取" icon="lock">
  此 mutation 需要具備 `MANAGE_SUBUSERS` scope 的 Bearer 權杖。
</Card>

```graphql theme={null}
mutation AssignObjectOwner(
  $objectType: ObjectOwnerObjectType!
  $objectId: UUID!
  $userId: UUID!
) {
  assignObjectOwner(
    objectType: $objectType
    objectId: $objectId
    userId: $userId
  ) {
    success
    objectOwnerId
    accountId
    objectType
    objectId
    userId
    createdAt
    error {
      code
      message
    }
  }
}
```

### 參數

| 參數           | 型別                       | 必填 | 說明                                                                           |
| :----------- | :----------------------- | :- | :--------------------------------------------------------------------------- |
| `objectType` | `ObjectOwnerObjectType!` | 是  | 使用 `SPEND_ACCOUNTS`。其他可用值有 `VIRTUAL_CARDS`、`GIFT_CARDS` 與 `FUNDING_SOURCES`。 |
| `objectId`   | `UUID!`                  | 是  | 步驟 1 回傳的 `userCashBalanceId`。                                                |
| `userId`     | `UUID!`                  | 是  | 授權使用者的 user ID。必須為呼叫者帳戶中的使用者。不是 `authUserId`。                                |

<Note>
  `assignObjectOwner` 只會為**尚未有擁有者**的物件指派擁有者。若該消費帳戶已經有擁有者，呼叫不會覆寫——請改用 [`transferObjectOwner`](#reassigning-ownership)。
</Note>

### 範例回應

```json theme={null}
{
  "data": {
    "assignObjectOwner": {
      "success": true,
      "objectOwnerId": "3c7a1b52-9e4d-4f88-a2c1-5d6e7f8a9b01",
      "accountId": "b41e2d90-6a77-4c35-9f12-8e0d3a4b5c6d",
      "objectType": "SPEND_ACCOUNTS",
      "objectId": "f8a3c9e1-7b2d-4f5e-9c8a-1d2e3f4a5b6c",
      "userId": "f1320ac4-52dc-4c67-9e80-24e506b18450",
      "createdAt": "2026-08-10T14:22:00.000Z",
      "error": null
    }
  }
}
```

### 回應欄位

| 欄位              | 型別                 | 說明                                               |
| :-------------- | :----------------- | :----------------------------------------------- |
| `success`       | `Boolean!`         | 指派是否已被紀錄。                                        |
| `objectOwnerId` | `UUID`             | 擁有權紀錄的 ID。**請保存此值**——`transferObjectOwner` 以此為鍵。 |
| `accountId`     | `UUID`             | 該物件與擁有者所屬的帳戶。                                    |
| `objectType`    | `String`           | 回傳物件領域，為 `SPEND_ACCOUNTS`。                       |
| `objectId`      | `UUID`             | 被指派擁有者的消費帳戶 ID。                                  |
| `userId`        | `UUID`             | 現在被紀錄為擁有者的使用者。                                   |
| `createdAt`     | `DateTime`         | 擁有權紀錄建立的時間。                                      |
| `error`         | `ObjectOwnerError` | 當 `success` 為 `false` 時的錯誤細節。                    |

***

## 重新指派擁有權

擁有權可透過 [`transferObjectOwner`](/api-reference/mutations/transfer-object-owner) 移轉，該呼叫使用先前指派所產生的 `objectOwnerId`，而非消費帳戶 ID。

```graphql theme={null}
mutation TransferObjectOwner($objectOwnerId: UUID!, $userId: UUID!) {
  transferObjectOwner(objectOwnerId: $objectOwnerId, userId: $userId) {
    success
    objectOwnerId
    objectId
    userId
    updatedAt
    error {
      code
      message
    }
  }
}
```

新擁有者必須是同一帳戶內的使用者。當某位授權使用者離開團隊且其消費帳戶需要移交給他人時，請使用此呼叫——移除授權使用者並不會重新指派其所擁有的物件。

***

## 完整流程

新增一位授權使用者，為其建立消費帳戶，並將其紀錄為該帳戶的擁有者。

**步驟 1 — 新增授權使用者。**

```curl theme={null}
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <account_owner_access_token>" \
  -d '{
  "query": "mutation AddAuthorizedUser($email: String, $roles: [UACRoleType!]!) { addAuthorizedUser(email: $email, roles: $roles) { success authUserId roles status error { code message } } }",
  "variables": {
    "email": "ada.lovelace@example.com",
    "roles": ["SPENDER"]
  }
}'
```

僅在 `status` 為 `ACTIVE` 時繼續。

**步驟 2 — 建立消費帳戶。**

```curl theme={null}
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <account_owner_access_token>" \
  -d '{
  "query": "mutation CreateUserCashBalance($input: CreateUserCashBalanceInput!) { createUserCashBalance(input: $input) { userCashBalanceId nickname availableCashBalance status createdAt } }",
  "variables": {
    "input": {
      "nickname": "Ada — Field Ops"
    }
  }
}'
```

**步驟 3 — 將授權使用者指派為擁有者。**

```curl theme={null}
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <account_owner_access_token>" \
  -d '{
  "query": "mutation AssignObjectOwner($objectType: ObjectOwnerObjectType!, $objectId: UUID!, $userId: UUID!) { assignObjectOwner(objectType: $objectType, objectId: $objectId, userId: $userId) { success objectOwnerId objectId userId createdAt error { code message } } }",
  "variables": {
    "objectType": "SPEND_ACCOUNTS",
    "objectId": "f8a3c9e1-7b2d-4f5e-9c8a-1d2e3f4a5b6c",
    "userId": "f1320ac4-52dc-4c67-9e80-24e506b18450"
  }
}'
```

**步驟 4 — 為其加值。** 消費帳戶起始餘額為零。可使用 [`depositCashBalance`](/features/deposit-from-external-accounts) 存入資金，或使用 [`transferInternalBalance`](/features/transfer-between-spend-accounts) 從另一個消費帳戶轉入，目標為新的 `userCashBalanceId`。

### TypeScript

```typescript theme={null}
const graphql = async (query: string, variables: Record<string, unknown>) => {
  const response = await fetch(
    'https://transactional-graph.staging.fluzapp.com/api/v1/graphql',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${accessToken}`,
      },
      body: JSON.stringify({ query, variables }),
    },
  );
  return response.json();
};

// 1. Create the spend account.
const created = await graphql(
  `mutation CreateUserCashBalance($input: CreateUserCashBalanceInput!) {
     createUserCashBalance(input: $input) {
       userCashBalanceId
       nickname
       status
     }
   }`,
  { input: { nickname: 'Ada — Field Ops' } },
);

const { userCashBalanceId } = created.data.createUserCashBalance;

// 2. Record the authorized user as its owner.
const assigned = await graphql(
  `mutation AssignObjectOwner(
     $objectType: ObjectOwnerObjectType!
     $objectId: UUID!
     $userId: UUID!
   ) {
     assignObjectOwner(
       objectType: $objectType
       objectId: $objectId
       userId: $userId
     ) {
       success
       objectOwnerId
       error { code message }
     }
   }`,
  {
    objectType: 'SPEND_ACCOUNTS',
    objectId: userCashBalanceId,
    userId: authorizedUserUserId,
  },
);

// Persist objectOwnerId — transferObjectOwner is keyed on it, not on the
// spend account ID.
const { objectOwnerId } = assigned.data.assignObjectOwner;
```

***

## 錯誤代碼

| 代碼          | 說明                                                        |
| :---------- | :-------------------------------------------------------- |
| `ARG-0001`  | 必要輸入缺漏或無效——`objectId` 不是呼叫者帳戶下的消費帳戶，或 `userId` 不是該帳戶的使用者。 |
| `AUTH-0008` | 無法解析 Bearer 權杖對應的呼叫者。請確認權杖有效。                             |
| `AUTH-0031` | 權杖缺少指派或移轉物件擁有權所需的 `MANAGE_SUBUSERS` scope。                |

***

<CardGroup cols={2}>
  <Card title="授權使用者概覽" icon="users" href="/features/authorized-user-overview">
    角色、狀態，以及授權使用者的完整生命週期。
  </Card>

  <Card title="為授權使用者建立虛擬卡" icon="credit-card" href="/features/create-virtual-card-for-authorized-user">
    使用 `authUserId` 代表授權使用者發卡。
  </Card>

  <Card title="消費帳戶概覽" icon="wallet" href="/features/spend-accounts">
    建立、讀取、編輯與關閉消費帳戶。
  </Card>

  <Card title="移除授權使用者" icon="user-minus" href="/features/remove-authorized-user">
    撤銷存取時，已擁有之物件會發生什麼事。
  </Card>
</CardGroup>
