Split A Payout

Split a payout into exact shares with compute helpers, then send each share through separate send_money steps.


A compute step paired with monetary_percent or monetary_split divides an amount into N parts that sum exactly to the input. No rounding loss. Each part feeds a separate send_money step.

Problem

You receive a single amount and need to distribute it across multiple beneficiaries: a parent share, a marketplace share, a fee account. Naive percentage math leaves rounding remainders unaccounted for. The Workflow API's monetary helpers handle the rounding deterministically.

Workflow definition

version: 1
name: "three-way-split"
description: "Split an incoming payment 60% merchant / 30% platform / 10% fee account"
steps:
    - name: "calc"
      compute:
        outputs:
          merchant_share: "monetary_percent(input.gross_amount, 6000)"
          platform_share: "monetary_percent(input.gross_amount, 3000)"
          fee_share:      "input.gross_amount - merchant_share - platform_share"
    - send_money:
        source:
            type: "wallet"
            account: "${input.platform_wallet}"
        destination:
            type: "wallet"
            account: "${input.merchant_wallet}"
            account_name: "${input.merchant_wallet_name}"
            bic: "PAEYPHM2XXX"
        provider: "paymongo"
        amount: "${steps.calc.output.merchant_share}"
        currency: "PHP"
        notes: "Merchant share"
    - send_money:
        source:
            type: "wallet"
            account: "${input.platform_wallet}"
        destination:
            type: "wallet"
            account: "${input.parent_wallet}"
            account_name: "${input.parent_wallet_name}"
            bic: "PAEYPHM2XXX"
        provider: "paymongo"
        amount: "${steps.calc.output.platform_share}"
        currency: "PHP"
        notes: "Platform share"
    - send_money:
        source:
            type: "wallet"
            account: "${input.platform_wallet}"
        destination:
            type: "wallet"
            account: "${input.fee_wallet}"
            account_name: "${input.fee_wallet_name}"
            bic: "PAEYPHM2XXX"
        provider: "paymongo"
        amount: "${steps.calc.output.fee_share}"
        currency: "PHP"
        notes: "Fee share"

The fee_share is computed as the residual (gross - merchant - platform) so the three amounts always sum exactly to gross_amount. This is the same trick monetary_split uses internally.

version: 1
name: "equal-three-way-split"
description: "Split an amount into three equal parts with deterministic rounding"
steps:
    - name: "calc"
      compute:
        outputs:
          # Returns []int64 of length 3; the first elements absorb the rounding remainder.
          shares: "monetary_split(input.gross_amount, 3)"
    - send_money:
        source: { type: "wallet", account: "${input.source_wallet}" }
        destination: { type: "wallet", account: "${input.dest1}", account_name: "${input.dest1_name}", bic: "PAEYPHM2XXX" }
        provider: "paymongo"
        amount: "${steps.calc.output.shares[0]}"
        currency: "PHP"
    - send_money:
        source: { type: "wallet", account: "${input.source_wallet}" }
        destination: { type: "wallet", account: "${input.dest2}", account_name: "${input.dest2_name}", bic: "PAEYPHM2XXX" }
        provider: "paymongo"
        amount: "${steps.calc.output.shares[1]}"
        currency: "PHP"
    - send_money:
        source: { type: "wallet", account: "${input.source_wallet}" }
        destination: { type: "wallet", account: "${input.dest3}", account_name: "${input.dest3_name}", bic: "PAEYPHM2XXX" }
        provider: "paymongo"
        amount: "${steps.calc.output.shares[2]}"
        currency: "PHP"

Trigger

Splits typically run on payout.deposited (event-based) or on a recurring schedule. See Event-Based Triggers and Schedule-Based Triggers for both forms.

What success looks like

The instance carries the computed split in step 0's output and three completed transfers in subsequent steps. The three transfer amounts sum exactly to input.gross_amount.

{
  "data": {
    "instance_id": "inst_xyz",
    "status": "completed",
    "output": {
      "steps_executed": 4,
      "step_outputs": [
        {"merchant_share": 600000, "platform_share": 300000, "fee_share": 100000},
        {"status": "completed", "transfer_id": "tr_a"},
        {"status": "completed", "transfer_id": "tr_b"},
        {"status": "completed", "transfer_id": "tr_c"}
      ]
    }
  }
}

Variations

  • Deduct a flat fee first. Add a net = input.gross_amount - flat_fee line before the percentage math.
  • Hard-coded percentages. Replace ${input.*} with literal centavo amounts if every share is fixed.
  • Different rails. Switch one or more send_money steps to provider: "auto" with destination.type: "bank" to land a share on a bank account.

See also