Card Lifecycle Management
Freezing Cards
Freeze a card temporarily to prevent unauthorized transactions while maintaining the card account.function freezeCard(workspaceAccountID: number, card: Card, currentUserAccountID: number) {
const cardID = card.cardID;
const previousFrozen = card?.nameValuePairs?.frozen ?? null;
const shouldUpdateCardList = card.accountID === currentUserAccountID;
const frozenData: CardListUpdateData = {
state: CONST.EXPENSIFY_CARD.STATE.STATE_SUSPENDED,
nameValuePairs: {
frozen: {
byAccountID: currentUserAccountID,
date: DateUtils.getDBTime(),
},
pendingFields: {frozen: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
},
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
isLoading: true,
errors: null,
};
const optimisticData = buildCardListUpdates(workspaceAccountID, cardID, frozenData, shouldUpdateCardList);
const parameters: FreezeCardParams = {
cardID,
};
API.write(WRITE_COMMANDS.FREEZE_CARD, parameters, {
optimisticData,
successData,
failureData,
});
}
Unfreezing Cards
Reactivate a frozen card to resume normal operations.function unfreezeCard(workspaceAccountID: number, card: Card, currentUserAccountID: number) {
const cardID = card.cardID;
const previousFrozen = card?.nameValuePairs?.frozen ?? null;
const shouldUpdateCardList = card.accountID === currentUserAccountID;
const unfrozenData: CardListUpdateData = {
state: CONST.EXPENSIFY_CARD.STATE.OPEN,
nameValuePairs: {
frozen: null,
pendingFields: {frozen: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
},
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
isLoading: true,
errors: null,
};
const optimisticData = buildCardListUpdates(workspaceAccountID, cardID, unfrozenData, shouldUpdateCardList);
const parameters: FreezeCardParams = {
cardID,
};
API.write(WRITE_COMMANDS.UNFREEZE_CARD, parameters, {
optimisticData,
successData,
failureData,
});
}
Card Limits
Updating Card Limits
Set spending limits for individual cards to control expenses.function updateExpensifyCardLimit(
workspaceAccountID: number,
cardID: number,
newLimit: number,
newAvailableSpend: number,
oldLimit?: number,
oldAvailableSpend?: number,
isVirtualCard?: boolean,
) {
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`,
value: {
[cardID]: {
availableSpend: newAvailableSpend,
nameValuePairs: {
unapprovedExpenseLimit: newLimit,
pendingFields: {unapprovedExpenseLimit: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
},
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
pendingFields: {availableSpend: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
isLoading: true,
errors: null,
},
},
},
];
const parameters: UpdateExpensifyCardLimitParams = {
cardID,
limit: newLimit,
isVirtualCard: isVirtualCard ?? false,
};
API.write(WRITE_COMMANDS.UPDATE_EXPENSIFY_CARD_LIMIT, parameters, {
optimisticData,
successData,
failureData,
});
}
Updating Limit Types
Configure different limit types (daily, monthly, etc.) with validity periods.function updateExpensifyCardLimitType(
workspaceAccountID: number,
cardID: number,
newLimitType: CardLimitType,
timeZone: SelectedTimezone | undefined,
oldCardNameValuePairs?: Card['nameValuePairs'],
validFrom?: string,
validThru?: string,
shouldClearValidityDates?: boolean,
) {
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`,
value: {
[cardID]: {
nameValuePairs: {
limitType: newLimitType,
pendingFields: {
limitType: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
validFrom: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
validThru: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
validFrom: shouldClearValidityDates ? null : validFrom,
validThru: shouldClearValidityDates ? null : validThru,
},
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
pendingFields: {availableSpend: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
isLoading: true,
errors: null,
},
},
},
];
const parameters: UpdateExpensifyCardLimitTypeParams = {
cardID,
limitType: newLimitType,
validFrom: validFrom ? DateUtils.normalizeDateToStartOfDay(validFrom, timeZone) : undefined,
validThru: validThru ? DateUtils.normalizeDateToEndOfDay(validThru, timeZone) : undefined,
clearValidityDates: shouldClearValidityDates,
};
API.write(WRITE_COMMANDS.UPDATE_EXPENSIFY_CARD_LIMIT_TYPE, parameters, {
optimisticData,
successData,
failureData,
});
}
Card Replacement
Replace lost, stolen, or damaged cards.type ReplacementReason = 'damaged' | 'stolen';
function requestReplacementExpensifyCard(
cardID: number,
reason: ReplacementReason,
validateCode: string
) {
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM | typeof ONYXKEYS.VALIDATE_ACTION_CODE>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM,
value: {
isLoading: true,
errors: null,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.VALIDATE_ACTION_CODE,
value: {
validateCodeSent: null,
},
},
];
const parameters: RequestReplacementExpensifyCardParams = {
cardID,
reason,
validateCode,
};
API.write(WRITE_COMMANDS.REQUEST_REPLACEMENT_EXPENSIFY_CARD, parameters, {
optimisticData,
successData,
failureData,
});
}
Fraud Detection
Report and handle fraudulent card activity.function reportVirtualExpensifyCardFraud(card: Card, validateCode: string) {
const cardID = card?.cardID ?? CONST.DEFAULT_NUMBER_ID;
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD | typeof ONYXKEYS.ACCOUNT>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
value: {
cardID,
isLoading: true,
errors: null,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.ACCOUNT,
value: {isLoading: true},
},
];
const parameters: ReportVirtualExpensifyCardFraudParams = {
cardID,
validateCode,
};
API.write(WRITE_COMMANDS.REPORT_VIRTUAL_EXPENSIFY_CARD_FRAUD, parameters, {
optimisticData,
successData,
failureData,
});
}
Deactivating Cards
Permanently deactivate a card.function deactivateCard(workspaceAccountID: number, card?: Card) {
const cardID = card?.cardID ?? CONST.DEFAULT_NUMBER_ID;
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST | typeof ONYXKEYS.CARD_LIST>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`,
value: {
[cardID]: null,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.CARD_LIST,
value: {
[cardID]: null,
},
},
];
const parameters: CardDeactivateParams = {
cardID,
};
API.write(WRITE_COMMANDS.CARD_DEACTIVATE, parameters, {optimisticData, failureData});
}
Deactivating a card is permanent and cannot be undone. Consider freezing the card instead if you may want to reactivate it later.
Updating Card Details
Card Title
function updateExpensifyCardTitle(
workspaceAccountID: number,
cardID: number,
newCardTitle: string,
oldCardTitle?: string
) {
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`,
value: {
[cardID]: {
nameValuePairs: {
cardTitle: newCardTitle,
pendingFields: {cardTitle: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
},
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
isLoading: true,
errors: null,
},
},
},
];
const parameters: UpdateExpensifyCardTitleParams = {
cardID,
cardTitle: newCardTitle,
};
API.write(WRITE_COMMANDS.UPDATE_EXPENSIFY_CARD_TITLE, parameters, {
optimisticData,
successData,
failureData,
});
}
Related Resources
Overview
Learn about Expensify Card basics
Company Cards
Managing company card integrations
