> ## 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.

# 為授權使用者建立虛擬卡

代表呼叫者帳戶中的授權使用者建立一張虛擬卡。傳入授權使用者的 `authUserId`（由 `addAuthorizedUser` 回傳的 UAC 角色指派 ID），即可為該使用者的底層持卡人紀錄建立卡片，同時將卡片範圍限制在呼叫者的帳戶內。

`authUserId` 必須屬於呼叫者的帳戶、狀態為 ACTIVE，且不能是 `OWNER` 指派。若 `addAuthorizedUser` 回傳 `PENDING`，則授權使用者必須先接受邀請，之後此 mutation 才能使用該 `authUserId`。

建立虛擬卡可使用已儲存的帳單地址（`userAddressId`）或內嵌的 `billingAddress`。對於特定優惠，提供任一地址值都會在發卡前觸發與發卡機構的帳單地址註冊。若在伺服器端等待時間後，發卡機構審核仍在處理中，mutation 會回傳 GraphQL 錯誤代碼 `VC-0020`，並包含 `extensions.addressId`；請以該值作為 `userAddressId` 重新嘗試。

🔒 存取受限

此 mutation 需要具備 `CREATE_VIRTUALCARD` 權限範圍的 Bearer 權杖。

```graphql theme={null}
mutation CreateVirtualCard($input: CreateVirtualCardInput!) {
  createVirtualCard(input: $input) {
    virtualCardId
    userId
    cardholderName
    expiryMonth
    expiryYear
    virtualCardLast4
    status
    cardType
    initialAmount
    usedAmount
    createdAt
    authorizationSetting {
      lockDate
      dailySpendLimit
      weeklySpendLimit
      monthlySpendLimit
    }
  }
}
```

<br />

### 參數

| 參數                         | 型別                             | 必填  | 說明                                                               |
| :------------------------- | :----------------------------- | :-- | :--------------------------------------------------------------- |
| input                      | CreateVirtualCardInput!        | Yes | 虛擬卡建立請求的包裹物件。                                                    |
| input.idempotencyKey       | UUID!                          | Yes | 唯一的用戶端產生 UUID。相同的 key 可避免同一請求被重複處理。                              |
| input.spendLimit           | Float!                         | Yes | 卡片可被扣款的最高金額。最小為 `$5`；最多允許兩位小數。                                   |
| input.offerId              | UUID                           | Yes | 虛擬卡優惠 ID。使用 `getVirtualCardOffers` 以擷取有效的優惠。                     |
| input.authUserId           | UUID                           | No  | 要代為建立卡片的授權使用者 ID（UAC 角色指派 ID）。必須為 ACTIVE 且非擁有者。                  |
| input.userAddressId        | UUID                           | No  | 呼叫者或授權持卡人的已儲存帳單地址 ID。優先於 `billingAddress`。                       |
| input.billingAddress       | VirtualCardBillingAddressInput | No  | 在發卡前要儲存並向卡片計畫註冊的新帳單地址。                                           |
| input.spendLimitDuration   | VirtualCardSpendLimitDuration  | No  | 卡片限額期間。預設為 `LIFETIME`。                                           |
| input.lockDate             | String                         | No  | 未來鎖卡日期。預設為自請求日起 47 個月。                                           |
| input.lockCardNextUse      | Boolean                        | No  | 是否在下一次使用後鎖卡。預設為 `false`。                                         |
| input.cardNickname         | String                         | No  | 卡片暱稱。提供時需為 1-50 個字元。                                             |
| input.primaryFundingSource | VirtualCardFundingSource       | No  | 主要資金來源。預設為 `FLUZ_BALANCE`。若為 `BANK_ACCOUNT`，則必填 `bankAccountId`。 |
| input.bankAccountId        | UUID                           | No  | 當 `primaryFundingSource` 為 `BANK_ACCOUNT` 時使用的銀行帳戶 ID。           |
| input.userCashBalanceId    | UUID                           | No  | 要附加到卡片的消費帳戶 ID。                                                  |
| input.usePrepaymentBalance | Boolean                        | No  | 當為 `false` 時，卡片不會動用預付餘額。預設為 `true`。                              |
| input.useRewardsBalance    | Boolean                        | No  | 當為 `false` 時，卡片不會動用獎勵餘額。預設為 `true`。                              |
| input.memo                 | String                         | No  | 交易附註。最大 255 個字元。                                                 |
| input.transactionCategory  | String                         | No  | 選填的分類名稱。系統會為帳戶尋找或建立相符分類。最大 100 個字元。                              |

<br />

### 回應

#### 成功回應

```json theme={null}
{
  "data": {
    "createVirtualCard": {
      "virtualCardId": "6d9f0d0f-21f0-4ad1-8fc7-2fb7dd58ce11",
      "userId": "f1320ac4-52dc-4c67-9e80-24e506b18450",
      "cardholderName": "Ada Lovelace",
      "expiryMonth": "08",
      "expiryYear": "2029",
      "virtualCardLast4": "4242",
      "status": "ACTIVE",
      "cardType": "MULTI_USE",
      "initialAmount": 100,
      "usedAmount": 0,
      "createdAt": "2026-05-15T15:18:00.000Z",
      "authorizationSetting": {
        "lockDate": "2029-08-15",
        "dailySpendLimit": null,
        "weeklySpendLimit": null,
        "monthlySpendLimit": null
      }
    }
  }
}
```

<br />

### 回應欄位

| 欄位                     | 型別       | 說明                                              |
| :--------------------- | :------- | :---------------------------------------------- |
| `virtualCardId`        | UUID     | 建立的虛擬卡 ID。                                      |
| `userId`               | UUID     | 持卡人的使用者 ID。當提供 `authUserId` 時，此欄位為授權使用者的使用者 ID。 |
| `cardholderName`       | String   | 顯示於虛擬卡上的持卡人姓名。                                  |
| `expiryMonth`          | String   | 虛擬卡到期月份。                                        |
| `expiryYear`           | String   | 虛擬卡到期年份。                                        |
| `virtualCardLast4`     | String   | 虛擬卡卡號末 4 碼。                                     |
| `status`               | String   | 虛擬卡狀態，例如 `ACTIVE`。                              |
| `cardType`             | String   | 虛擬卡類型。                                          |
| `initialAmount`        | Float    | 該卡片請求的初始消費限額。                                   |
| `usedAmount`           | Float    | 卡片已消費金額。                                        |
| `createdAt`            | DateTime | 建立卡片的時間。                                        |
| `authorizationSetting` | Object   | 附加至虛擬卡的授權設定。                                    |

<br />

### 範例請求

為授權使用者使用已儲存地址建立卡片：

```curl theme={null}
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_access_token>" \
  -d '{
  "query": "mutation CreateVirtualCard($input: CreateVirtualCardInput!) { createVirtualCard(input: $input) { virtualCardId userId cardholderName virtualCardLast4 status cardType initialAmount usedAmount createdAt } }",
  "variables": {
    "input": {
      "idempotencyKey": "931e8841-cf23-4f36-8bf8-169384042ec2",
      "offerId": "09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9",
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "userAddressId": "1f6b2c3d-4e5f-4a67-9a10-2b3c4d5e6f70",
      "spendLimit": 100,
      "spendLimitDuration": "LIFETIME",
      "cardNickname": "Ada Travel Card",
      "primaryFundingSource": "FLUZ_BALANCE"
    }
  }
}'
```

為授權使用者使用新的內嵌帳單地址建立卡片：

```curl theme={null}
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_access_token>" \
  -d '{
  "query": "mutation CreateVirtualCard($input: CreateVirtualCardInput!) { createVirtualCard(input: $input) { virtualCardId userId cardholderName virtualCardLast4 status cardType initialAmount usedAmount createdAt } }",
  "variables": {
    "input": {
      "idempotencyKey": "c20341f0-47e3-4d52-8361-1d7c37736b65",
      "offerId": "09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9",
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "spendLimit": 100,
      "billingAddress": {
        "streetAddressLine1": "456 Market St",
        "streetAddressLine2": "Suite 200",
        "country": "United States",
        "city": "San Francisco",
        "state": "CA",
        "postalCode": "94105"
      }
    }
  }
}'
```

```typescript theme={null}
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: `
      mutation CreateVirtualCard(
        $input: CreateVirtualCardInput!
      ) {
        createVirtualCard(input: $input) {
          virtualCardId
          userId
          cardholderName
          virtualCardLast4
          status
          cardType
          initialAmount
          usedAmount
          createdAt
        }
      }
    `,
    variables: {
      input: {
        idempotencyKey: '931e8841-cf23-4f36-8bf8-169384042ec2',
        offerId: '09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9',
        authUserId: '8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d',
        userAddressId: '1f6b2c3d-4e5f-4a67-9a10-2b3c4d5e6f70',
        spendLimit: 100,
        spendLimitDuration: 'LIFETIME',
        cardNickname: 'Ada Travel Card',
        primaryFundingSource: 'FLUZ_BALANCE',
      },
    },
  }),
});

const data = await response.json();

if (data.errors?.[0]?.extensions?.code === 'VC-0020') {
  const userAddressId = data.errors[0].extensions.addressId;
  console.log('Billing address pending issuer approval. Retry with userAddressId:', userAddressId);
} else {
  console.log('Virtual card created:', data.data.createVirtualCard);
}
```

### 完整流程：註冊使用者、加入授權使用者、加入地址、建立卡片

此流程會註冊新的 Fluz 使用者，將該使用者加入呼叫者的帳戶為授權使用者，為該授權持卡人儲存帳單地址，接著代表他們建立虛擬卡。

步驟 1：註冊使用者。這需要對啟用註冊且狀態為 ACTIVE 的應用程式之開發者使用者，提供 Bearer 權杖。

```curl theme={null}
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <developer_access_token>" \
  -d '{
  "query": "mutation RegisterUser($firstName: String!, $lastName: String!, $phoneNumber: String!, $regionCode: String!, $emailAddress: String!, $dateOfBirth: String!) { registerUser(firstName: $firstName, lastName: $lastName, phoneNumber: $phoneNumber, regionCode: $regionCode, emailAddress: $emailAddress, dateOfBirth: $dateOfBirth) { success error { code message } } }",
  "variables": {
    "firstName": "Ada",
    "lastName": "Lovelace",
    "phoneNumber": "5555555555",
    "regionCode": "US",
    "emailAddress": "ada.lovelace@example.com",
    "dateOfBirth": "1990-01-31"
  }
}'
```

步驟 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 AddAuthorizedUser($email: String, $roles: [UACRoleType!]!) { addAuthorizedUser(email: $email, roles: $roles) { success authUserId roles status pendingActionId error { code message } } }",
  "variables": {
    "email": "ada.lovelace@example.com",
    "roles": ["SPENDER"]
  }
}'
```

只有在回傳的 `status` 為 `ACTIVE` 後才能繼續。若狀態為 `PENDING`，則在 `addVirtualCardAddress` 或 `createVirtualCard` 能使用回傳的 `authUserId` 前，授權使用者必須先接受邀請。

步驟 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 AddVirtualCardAddress($input: AddVirtualCardAddressInput!) { addVirtualCardAddress(input: $input) { userAddressId streetAddressLine1 streetAddressLine2 country city state postalCode } }",
  "variables": {
    "input": {
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "billingAddress": {
        "streetAddressLine1": "456 Market St",
        "streetAddressLine2": "Suite 200",
        "country": "United States",
        "city": "San Francisco",
        "state": "CA",
        "postalCode": "94105"
      }
    }
  }
}'
```

步驟 4：使用已儲存地址為授權使用者建立虛擬卡。

```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 CreateVirtualCard($input: CreateVirtualCardInput!) { createVirtualCard(input: $input) { virtualCardId userId cardholderName virtualCardLast4 status cardType initialAmount usedAmount createdAt } }",
  "variables": {
    "input": {
      "idempotencyKey": "931e8841-cf23-4f36-8bf8-169384042ec2",
      "offerId": "09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9",
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "userAddressId": "1f6b2c3d-4e5f-4a67-9a10-2b3c4d5e6f70",
      "spendLimit": 100,
      "spendLimitDuration": "LIFETIME",
      "cardNickname": "Ada Travel Card",
      "primaryFundingSource": "FLUZ_BALANCE"
    }
  }
}'
```

### 錯誤代碼

| 代碼          | 訊息                                                                                                                 | 說明                                                                                                                                                     |
| :---------- | :----------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ARG-0001`  | Invalid arguments received                                                                                         | 必填輸入遺漏或無效、`spendLimit` 低於 `$5`、`lockDate` 非未來時間、`offerId` 無效、`authUserId` 無效、`userAddressId` 不屬於該帳戶/持卡人，或選擇 `BANK_ACCOUNT` 作為資金來源但未提供 `bankAccountId`。 |
| `AUTH-0008` | Invalid user access                                                                                                | Bearer 權杖無法對應到呼叫者。請確認權杖有效。                                                                                                                             |
| `AUTH-0031` | The requested scopes must be granted by the user first.                                                            | 權杖缺少建立虛擬卡所需的 `CREATE_VIRTUALCARD` 權限範圍。                                                                                                                |
| `AUTH-0034` | No authorized user found with this id on the caller's account.                                                     | `authUserId` 不存在於呼叫者的帳戶上、非 ACTIVE，或指向 OWNER 指派。                                                                                                        |
| `VC-0001`   | Please try another payment method. If you continue experiencing issues, please contact our support team.           | 無法建立卡片或發卡機構拒絕了帳單地址。                                                                                                                                    |
| `VC-0019`   | We are unable to get the virtual card offer. If you continue experiencing issues, please contact our support team. | 無法解析請求的虛擬卡優惠。                                                                                                                                          |
| `VC-0020`   | Virtual card billing address is pending approval. Please retry shortly using the returned addressId.               | 帳單地址已提交給發卡機構，但在伺服器端等待視窗結束前尚未核准。請使用 `extensions.addressId` 作為 `userAddressId` 重新嘗試。                                                                     |

<br />
