authUserId(由 addAuthorizedUser 返回的 UAC 角色分配 ID),即可为该用户的底层持卡人记录创建卡片,同时将卡片作用域限定在调用方的账户内。
authUserId 必须属于调用方的账户,且必须为 ACTIVE,且不能是 OWNER 分配。如果 addAuthorizedUser 返回 PENDING,则授权用户必须先接受邀请,此变更操作才可使用该 authUserId。
创建虚拟卡时可使用已保存的账单地址(userAddressId)或内联的 billingAddress。对于部分优惠,提供任一地址值都会在发卡前触发向发卡行注册账单地址。如果在服务器端等待窗口结束后发卡行审批仍在进行中,此变更将返回 GraphQL 错误码 VC-0020,并带有 extensions.addressId;使用该值作为 userAddressId 重试。
🔒 受限访问
此变更需要携带具有 CREATE_VIRTUALCARD 范围的 Bearer 令牌。
mutation CreateVirtualCard($input: CreateVirtualCardInput!) {
createVirtualCard(input: $input) {
virtualCardId
userId
cardholderName
expiryMonth
expiryYear
virtualCardLast4
status
cardType
initialAmount
usedAmount
createdAt
authorizationSetting {
lockDate
dailySpendLimit
weeklySpendLimit
monthlySpendLimit
}
}
}
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 个字符。 |
Response
Success Response
{
"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
}
}
}
}
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 | 附加到虚拟卡的授权设置。 |
Example Requests
为授权用户使用已保存地址创建卡: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 -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"
}
}
}
}'
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 -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"
}
}'
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 -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"
}
}
}
}'
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 重试。 |