Skip to content

Adhoc partial balance settlement for Expensify Card #100419

Description

@joekaufmanexpensify

@JmillsExpensify and I were discussing recent customer feedback about wanting to adhoc partially settle Expensify Card balance and decided this is a feature worth offering for the card. Note: the full monthly settlement is still due on the settlement date. This would just provide a way to partially pay some of the balance before it is all due, NOT an option to carry a balance.

Details

  • Today, the "Settle balance" feature (available only on monthly settlement) only supports settling the entire current balance early. There's no way to pay down part of it early.
  • The command backing this (QueueExpensifyCardForBilling in Auth) only takes a domain/feed identifier, no amount, it just flags the domain for billing. The actual billing job (BillExpensifyCards) then bills every outstanding captured transaction for that domain/program, whatever that adds up to be at the time it runs. This means "full balance" is never a frozen snapshot, it bills whatever's outstanding once the job runs (next business day), including any new transactions captured between now and then.
  • Now, we'll optionally let admins choose to settle a partial amount instead, only while on monthly settlement (same precondition as today).
  • Rounding rule: since settlements need to map cleanly to a discrete set of transactions in the reconciliation view, a partial amount is rounded up from what the admin enters to the nearest amount that matches a whole number of settled transactions (increasing by increments of the smallest settled transaction until it lands on one).
  • UI flow: I'm thinking the cleanest way to do this is to move "Settle balance" from the existing center confirmation modal into a right-hand pane, split into two pages. Curious if the design team agrees with that, though. Assuming, we do go ahead with that, tapping "Settle Balance" would:
    • Page 1: Open a RHP with a forced choice between "Settle current balance" and "Settle partial balance," defaulting to "Settle current balance". Selecting "Settle partial balance" reveals an inline amount input on the same page. The bottom button always says "Next" and always just advances to page 2 with whatever's selected, it never fires the settle action directly.
      • Partial balance input is a required field. Can't be $0 or negative. Can't exceed full current balance.
    • Page 2 (confirmation): always shown, for both full and partial, so the flow is consistent regardless of choice.
      • Full selected: shows similar copy as today's modal ("This will settle your current balance the next business day. Once successful, the amount will be added back to your remaining limit."). No dollar amount shown here, since the actual amount isn't fixed until the billing job runs.
      • Partial selected: shows the amount that will actually be settled (the rounded-up amount, computed when navigating from page 1 to page 2), and explains that it's been rounded up from what they entered to match a whole number of transactions.
    • The bottom button says "Settle balance" and always does the same thing: commit whatever amount this page is showing.
    • Post-settlement confirmation message: the existing "Balance will be settled on [date]" message below the balance updates based on what was queued:
      • Full: "Full balance will be settled on [date]."
      • Partial: "$[rounded amount] will be settled on [date]."
    • Monthly to daily switch: switching settlement frequency from monthly to daily while a partial settlement is queued and not yet processed is allowed, but we'll show a warning that doing so will settle the full balance (not just the queued partial amount) on the next daily run, since daily settlement has no concept of a partial amount. This requires the frequency-switch flow to check for a queued settlement, which it doesn't do today.
  • Once a partial settlement is queued, it can't be edited or canceled until that day's settlement processes.
  • No changes needed on the Spend page. Settlements are already grouped by entryID/withdrawalID there, and a partial settlement is just another entryID scoped to whichever transactions make up the rounded amount. It'll show up as its own settlement row like any other.
  • Cash back: partial settlements mean a single month can now have multiple settlement entries (the partial and the remainder), which raises an open question on when cash back gets paid for that month. Flagging for input:
    • Pay per entry (today's default behavior): cash back credits each settlement entry as soon as it individually clears. This means a month's cash back could get split into two separate payouts, one for the partial portion and one for the remainder, on different dates.
    • Hold until the whole month clears: don't pay out any cash back for the month until every settlement entry from that month (partial and remainder) has cleared. Requires new logic, since today's calculation credits each settled entry independently rather than waiting for a full set.
  • Failed partial settlement: if a queued partial settlement debit fails, we'll handle it the same as a failed full settlement today. This locks the settlement bank account and suspends all cards on the domain until the failure clears. No new behavior needed here, just calling it out.

Existing settle balance confirmation modal

Image

Existing balanace queued confirmation message

Image

Switching from monthly to daily settlement today (occurs in RHP)

2026-09-04_14-18-20.mp4

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

DailyKSv2NewFeatureSomething to build that is a new item.PlanningChanges still in the thought process

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions