@cfxlabsinc/b2b-services
    Preparing search index...
    MatcherCriteria: Partial<
        {
            bankId: BankId;
            cashDepositRetailerId: string;
            countryCode: string;
            dayOfWeek: number;
            entityType: "IDENTITY"
            | "ORGANIZATION";
            fboAccountNumber: string;
            hasIdentityDocument: boolean;
            ledgerAccountId: string;
            ledgerProgramId: string;
            productId: ProductName;
            regionCode: string;
            sourceAmount: BigNumber | number;
            sourceCurrency: string;
            sourceWalletType: SourceWalletType;
            speed: Speed;
            targetAmount: BigNumber | number;
            targetCurrency: string;
            timeOfDay: string;
            usage24hCount: BigNumber | number;
            usage24hUsd: BigNumber | number;
            usage30dCount: BigNumber | number;
            usage30dUsd: BigNumber | number;
            usage7dCount: BigNumber | number;
            usage7dUsd: BigNumber | number;
            usageCalendarMonthCount: BigNumber | number;
            usageCalendarMonthUsd: BigNumber | number;
            verificationByo: boolean;
            victorCounterpartyId: string;
            virtualAccountId: string;
            virtualAccountNumber: string;
            virtualAccountProvider: string;
            virtualAccountStatus: "ACTIVE" | "PENDING";
        },
    >

    All fields that can appear in the criteria payload passed to b2b.rule_match. Route-scoped fields (bankId, speed) and entityType are injected by the SQL search layer — callers don't set them directly, but they are valid matcher fields because rules can target them.

    Rolling-window usage fields (usage{24h,7d,30d}{Usd,Count}) are pre-fetched by ProductQuoteService and passed through so fee/limit/activation rules can branch on the customer's prior volume — e.g. "charge 0bps once 30D volume crosses $1M". Set when the caller supplies getUsage; absent in estimate-mode callers.