Appearance
Config tables
Per-merchant configuration that drives the orchestrator + composer + workers.
MerchantFee — fee rules
Per-merchant rate cards. One row per direction × type × match key with an effective window. Resolved at event time by lib/fees/resolver.ts:pickBestMatch — most specific match wins.
| Column | Type | Notes |
|---|---|---|
merchantId | String | |
direction | FeeDirection | in (Vecnet pays processor) · out (merchant pays Vecnet) |
feeType | FeeType | acceptance · refund · chargeback · decline · three_ds · antifraud · settlement |
channel | FeeChannel | online · terminal · any |
paymentMethod | FeePaymentMethod | card · spei · oxxo · mercadopago · paysafe · terminal_card · any |
cardBrand | FeeCardBrand? | visa · mastercard · amex |
cardType | FeeCardType? | credit · debit |
installments | Int? | |
rateBps | Int | Basis points (1 bp = 0.01%) |
fixedAmountCents | BigInt | |
minFeeCents, maxFeeCents | BigInt? | Clamp range |
ivaRateBps | Int @default(0) | IVA in basis points (Mexico = 1600) |
ivaIncluded | Bool @default(false) | If true, rate is tax-inclusive and split at calc time |
effectiveFrom, effectiveTo | DateTime |
Calculation lives in lib/fees/calculator.ts:
fee = clamp(amountCents * rateBps / 10000 + fixedAmountCents, min, max)With IVA, calculateFeeWithIva() returns { feeCents, ivaCents, totalCents }.
MerchantRollingReserveConfig
One active config per (merchant, channel). The orchestrator reads the active row on every successful payment and withholds gross * reserveRateBps / 10000 for holdingPeriodDays days.
| Column | Type | Notes |
|---|---|---|
merchantId | String | |
channel | ReserveChannel | online · terminal (rolling reserve is channel-scoped) |
reserveRateBps | Int | Basis points |
holdingPeriodDays | Int @default(90) | |
enabled | Bool @default(true) | |
effectiveFrom, effectiveTo | DateTime |
@@unique([merchantId, channel, effectiveFrom]) — append-only config history.
MerchantSettlementConfig — cycle config
One per merchant.
| Column | Type | Notes |
|---|---|---|
cycleType | SettlementCycleType | daily · weekly · biweekly · monthly · t_plus_n |
weeklyDayOfWeek, biweeklyDayOfWeek, biweeklyAnchorDate, monthlyDayOfMonth, tPlusN | various | Cycle-type-specific |
timezone | String @default("America/Mexico_City") | |
minimumPayoutCents | BigInt @default(0) | Below this, the cycle rolls into the next |
cutoffHourLocal | Int @default(17) | Local hour the cycle closes |
emailRecipients | String[] |
Period math lives in lib/settlements/scheduler.ts:computeDuePeriod — returns { start, end } for the most recent cutoff <= now.
MerchantFinanceConfig — module flags
NEW in Phase 1 (Tonder usrv-finances port). Per-merchant booleans mirroring Tonder's ConfigTable. Recorded but not yet enforced by the writers — they're surfaced on the merchant Finance config tab so finops can flip them, with enforcement rolled out per-writer once the product call is made.
prisma
model MerchantFinanceConfig {
merchantId String @id
enableFees Boolean @default(true)
enableLedger Boolean @default(true)
enableSettlements Boolean @default(true)
enableDailySnapshots Boolean @default(true)
updatedAt DateTime @updatedAt
}Edited via PATCH /api/admin/merchants/[id]/finance-config; zod schema at lib/schemas/finance-config.ts.
MerchantFeatures — channels + payment methods
| Column | Notes |
|---|---|
onlineEnabled, terminalEnabled | Channels |
cardEnabled, speiEnabled, oxxoEnabled, mercadopagoEnabled, paysafeEnabled | Payment methods. "Cash vouchers" label = paysafeEnabled |
paymentLinksEnabled | Other |
MerchantCheckoutConfig — branding only
Logo URL + 4 brand colors. Everything else (locale, footer, button shape, preview, links) was dropped during the Tonder-scope trim.
MerchantApiKey
Live + test keys. The full secret is shown once on creation; the database stores bcrypt-hashed.
AdminUser
Vecnet operators. Bound to Clerk via clerkId. See auth-rls. Holds role (superadmin · finops · integrations), lastLoginAt, audit FKs. No password column — Clerk owns credentials.