Skip to main content

Partial Settlement

Sometimes a marketplace doesn't want to release everything in one shot — maybe an order ships in stages, maybe a policy holds a fraction back for a return window. executeSettlement takes an optional amount: leave it out and Ishtaran settles everything still reserved; pass it, and Ishtaran settles exactly that much, as many times as there's a balance left.

Transaction = 200.00

Settlement #1 amount=50 → fee=0.45 remaining=150.00 PARTIALLY_SETTLED
Settlement #2 amount=70 → fee=0.63 remaining=80.00 PARTIALLY_SETTLED
Settlement #3 amount=80 → fee=0.72 remaining=0.00 SETTLED

Code

examples/marketplace-mercatto/scenarios/settlement-partial.ts
async function settlePartial(amount: string) {
const settlement = await mercatto.settlements.executeSettlement(transactionId, amount);
const full = await mercatto.settlements.get(settlement.settlementId);
const summary = await mercatto.settlements.getSummary(transactionId);
const state = await mercatto.transactions.getState(transactionId);
console.log(`amount=${amount} fee=${full.platformFeeAmount} remaining=${summary.remainingReservedAmount} status=${state.status.name}`);
}

await settlePartial('50'); // fee=0.45 remaining=150.00 PARTIALLY_SETTLED
await settlePartial('70'); // fee=0.63 remaining=80.00 PARTIALLY_SETTLED
await settlePartial('80'); // fee=0.72 remaining=0.00 SETTLED

What happened under the hood

Each call computes its own Fee, on its own slice — never on the Transaction's original total. 0.9% of 50 is 0.45, not a proportional share of the eventual 1.80. Sum the three Fees and the three Splits across all three calls and they land on the exact same totals as one single 200 Settlement would have (Fee 1.80, Bob 178.38, Mercatto 19.82) — partial Settlement only ever changes when money moves, never how much, confirmed by running both paths and comparing.

A real gap this Business Case found and fixed. The platform's own domain logic always supported a partial amount — but the public HTTP contract never sent it until this Business Case's audit caught the gap and it was activated (BL-STL-008). Requesting more than what's left (amount > remaining) is rejected outright, never silently capped — see Failure scenarios.

A real, expected wrinkle worth knowing: firing partial Settlements back-to-back on the same Transaction can occasionally hit a genuine 409 CONCURRENT_MODIFICATION — standard optimistic concurrency on a busy row, not a financial bug. The correct response is the same as any optimistic-concurrency API: retry once. See Known Limitations §F.15.