> ## 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`，则授权用户必须先接受邀请，此变更操作才可使用该 `authUserId`。

创建虚拟卡时可使用已保存的账单地址（`userAddressId`）或内联的 `billingAddress`。对于部分优惠，提供任一地址值都会在发卡前触发向发卡行注册账单地址。如果在服务器端等待窗口结束后发卡行审批仍在进行中，此变更将返回 GraphQL 错误码 `VC-0020`，并带有 `extensions.addressId`；使用该值作为 `userAddressId` 重试。

🔒 受限访问

此变更需要携带具有 `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 />

### Parameters

| Parameter                  | Type                           | Required | Description                                                        |
| :------------------------- | :----------------------------- | :------- | :----------------------------------------------------------------- |
| input                      | CreateVirtualCardInput!        | Yes      | 虚拟卡创建请求的封装对象。                                                      |
| input.idempotencyKey       | UUID!                          | Yes      | 客户端生成的唯一 UUID。相同的键可防止同一请求被多次处理。                                    |
| input.spendLimit           | Float!                         | Yes      | 可在卡上扣款的最高金额。最低为 `$5`；最多允许两位小数。                                     |
| input.offerId              | UUID                           | Yes      | 虚拟卡优惠 ID。使用 `getVirtualCardOffers` 获取有效优惠。                         |
| input.authUserId           | UUID                           | No       | 要代表其创建卡片的授权用户 ID（UAC 角色分配 ID）。必须为 ACTIVE 且非 owner。                 |
| 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 />

### Response

#### Success Response

```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 />

### Response Fields

| Field                  | Type     | Description                                |
| :--------------------- | :------- | :----------------------------------------- |
| `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 />

### Example Requests

为授权用户使用已保存地址创建卡：

```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"
    }
  }
}'
```

### Error Codes

| Code        | Message                                                                                                            | Description                                                                                                                                             |
| :---------- | :----------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `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 />
