Appearance
Fee Rules CRUD
Fee rule management: creation, querying, updates, and the specificity-based matching algorithm.
Overview
| Attribute | Value |
|---|---|
| Service | src/service/FeeRulesService.ts |
| Calculator | src/service/FeesCalculatorService.ts |
| Storage | MongoDB financesFeeRules collection |
| Schemas | src/schema/fee_rule.json, fee_rule_request.json |
Fee Rule Model
Common Fields (all rule types)
| Field | Type | Description |
|---|---|---|
_id | ObjectId | MongoDB document ID |
fee_rule_key | string | Unique key for deduplication |
rule_type | string | PAYIN or WITHDRAWAL |
fee_type | string | IN (acquirer-side) or OUT (business-side). Unified format nests these under in/out. |
status | string | active or inactive |
description | string | Human-readable description |
Match Criteria
These fields determine which transactions a rule applies to. null means "matches all" (generic rule).
| Field | Type | Description |
|---|---|---|
business_id | string[]? | Specific business IDs, or null for all businesses |
acquirer | string[]? | Acquirer names (e.g., ["kushki", "unlimit"]) |
currency_code | string? | ISO currency code |
country_code | string[]? | Merchant country codes |
payment_method_id | number[]? | Payment method IDs |
card_brand | string[]? | Card brands (Visa, Mastercard, etc.) |
risk_level | string[]? | Risk classifications |
Fee Fields — PAYIN
| Field | Description |
|---|---|
intra_transaction_rate | Domestic transaction fee percentage |
intra_transaction_fee | Domestic fixed fee per transaction |
inter_transaction_rate | International transaction fee percentage |
inter_transaction_fee | International fixed fee per transaction |
minimum_fee | Minimum fee floor (applied when calculated fee is lower) |
iva_rate | IVA/VAT rate percentage |
hold_reserve_percentage | Rolling reserve hold percentage |
hold_reserve_period | Rolling reserve hold period in days |
chargeback_fee | Fixed fee per chargeback/dispute |
refund_fee | Fixed fee per refund |
Fee Fields — WITHDRAWAL
| Field | Description |
|---|---|
intra_transaction_rate | Withdrawal fee percentage |
intra_transaction_fee | Fixed fee per withdrawal |
minimum_fee | Minimum fee floor |
iva_rate | IVA/VAT rate percentage |
method | Withdrawal method |
transaction_type | WITHDRAWAL or TOPUP |
Settlement Policy (nested)
| Field | Description |
|---|---|
settlement_policy.type | fixed_days_delay or windows |
settlement_policy.fixed_days_delay.days | Number of days delay |
settlement_policy.settlement_hour | Hour of day for settlement (UTC) |
settlement_policy.settlement_periods | Array of settlement period configurations |
Rule Formats
Unified Format (recommended)
Groups IN and OUT sides under a single document:
json
{
"rule_type": "PAYIN",
"in": { "intra_transaction_rate": 2.9, "intra_transaction_fee": 3.0, ... },
"out": { "intra_transaction_rate": 1.5, "intra_transaction_fee": 1.0, ... },
"acquirer": ["kushki"],
"currency_code": "MXN",
...
}Legacy Flat Format
Separate documents per fee_type:
json
{
"rule_type": "PAYIN",
"fee_type": "IN",
"intra_transaction_rate": 2.9,
"intra_transaction_fee": 3.0,
...
}Both formats are supported. The unified format is preferred for new rules.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/fee-rules | Create a new fee rule |
GET | /v1/fee-rules | List fee rules with filters |
GET | /v1/fee-rules/{id} | Get fee rule by ID |
PATCH | /v1/fee-rules/{id} | Update fee rule fields |
DELETE | /v1/fee-rules/{id} | Delete fee rule |
Specificity Ranking Algorithm
When calculating fees for a transaction, the system finds the most specific matching rule using a MongoDB aggregation pipeline:
- Filter: Match by
rule_type,status: active,fee_type(or unified format), and all applicable criteria fields - Rank: Calculate
_rankscore — lower is more specific:business_idmatch = 0, null = 1risk_levelmatch = 0, null = 1card_brandmatch = 0, null = 1
- Sort: Ascending by
_rank(most specific first) - Limit: Take the first result (most specific rule wins)
Example: A rule with business_id: ["abc"] + card_brand: ["Visa"] (rank 0+0=0) beats a generic rule with business_id: null + card_brand: null (rank 1+1=2).
NULL handling: Fields set to null match any value (generic). The $or conditions check both $exists: false and explicit null.
Fee Calculation Formulas
See Fee Calculation Flow for detailed formulas per detail type (PAYMENT, REFUND, DISPUTE, VOID, WITHDRAWAL).
Summary:
- PAYMENT/APMS:
fee = max(amount × rate/100 + fixed_fee, minimum_fee),net = amount - fee - iva - rolling_reserve - REFUND:
fee = refund_fee,net = amount + fee + iva - DISPUTE:
fee = chargeback_fee,net = amount + fee + iva(or justfee + ivaif merchant won) - VOID: All fees = 0,
net = amount - WITHDRAWAL/TOPUP:
fee = max(amount × rate/100 + fixed_fee, minimum_fee),net = amount