authUserId(由 addAuthorizedUser 回傳的 UAC 角色指派 ID),即可為該使用者的底層持卡人紀錄建立卡片,同時將卡片範圍限制在呼叫者的帳戶內。
authUserId 必須屬於呼叫者的帳戶、狀態為 ACTIVE,且不能是 OWNER 指派。若 addAuthorizedUser 回傳 PENDING,則授權使用者必須先接受邀請,之後此 mutation 才能使用該 authUserId。
建立虛擬卡可使用已儲存的帳單地址(userAddressId)或內嵌的 billingAddress。對於特定優惠,提供任一地址值都會在發卡前觸發與發卡機構的帳單地址註冊。若在伺服器端等待時間後,發卡機構審核仍在處理中,mutation 會回傳 GraphQL 錯誤代碼 VC-0020,並包含 extensions.addressId;請以該值作為 userAddressId 重新嘗試。
🔒 存取受限
此 mutation 需要具備 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
}
}
}
參數
| 參數 | 型別 | 必填 | 說明 |
|---|---|---|---|
| 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 個字元。 |
回應
成功回應
{
"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
}
}
}
}
回應欄位
| 欄位 | 型別 | 說明 |
|---|---|---|
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 | 附加至虛擬卡的授權設定。 |
範例請求
為授權使用者使用已儲存地址建立卡片: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"
}
}
}'
錯誤代碼
| 代碼 | 訊息 | 說明 |
|---|---|---|
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 重新嘗試。 |