Back to Hyperswitch

Decide Gateway: Multi-Objective Routing

api-reference/decision-engine-api-reference/api-reference/guides/run-transactions/decide-gateway-multi-objective.mdx

2026.08.10.08.7 KB
Original Source

Decide Gateway: Multi-Objective Routing

What multi-objective routing is

Plain success-rate (SR) routing optimises a single objective: send each payment to the gateway most likely to authorise it. But the cheapest path to a successful payment is not always the one with the highest auth rate — a gateway that is one point worse on auth but materially cheaper per transaction can leave the merchant with more money in hand. Multi-objective routing balances two objectives at once — authorisation and processing cost — so routing maximises the merchant's economic outcome, not just the raw approval odds.

It is implemented as a cost-aware post-step layered on top of SR scoring, not a replacement for it. The SR scorer runs first and produces its usual ranking; the post-step then takes those scores, attaches a per-gateway fee estimate to each, and re-ranks the candidates on expected value. Because it only ever runs after SR scoring, everything SR gives you (dimension-level buckets, elimination, hedging) is preserved — cost is simply an additional lens applied at the end.

How the ranking works

After the success-rate scorer picks its head gateway, the engine fetches per-PSP fee estimates and re-ranks every gateway that has cost data on economic value:

Economic value (EV) = auth rate × settlement value
settlement value = txn amount − cost of payment processing (acquirer, issuer & network fee)

The settlement value is derived from the merchant's margin and the per-PSP cost estimate (see the margin field on Create success-rate config).

If a cheaper PSP has a strictly higher expected value than the SR head, it is promoted (outcome: COST_WON) and routing_approach becomes SR_SELECTION_MULTI_OBJECTIVE. Otherwise the SR head is kept (outcome: AUTH_WON) and routing_approach keeps its normal SR value. Either way, the response carries a multi_objective_info block explaining the decision — which gateway SR would have picked, which one cost analysis chose, and by how much — so every cost-driven override is auditable.

Enablement

SwitchScopeBehaviour
multi_objective_routing_enabled feature flagMerchantPrimary rollout switch. Used whenever the request omits enableMultiObjective.
enableMultiObjective request fieldPer requestOptional boolean override. true forces the post-step on, false forces it off, omitted falls back to the merchant flag.

Notes:

  • The post-step only runs on SR-scored decisions and is skipped while hedging (exploration) is active for the transaction.
  • margin (fraction of ticket, e.g. 0.20) comes from the merchant's success-rate config — see Create success-rate config. It defaults to 1.0 when unset.
  • This post-step re-ranks the SR scores it is handed; it does not tune them. Autopilot is the separate self-tuning job that calibrates SR hedging and bucket size, and can run alongside this post-step (they are independent dials — enableMultiObjective and use_autopilot).
  • Gateways without fee data cannot be ranked on expected value and never win on cost; if the SR head itself has no fee data, the SR order is kept.
  • Per-gateway fee data comes from cost ingestion — settlement reports and invoices fitted into a per-cluster cost model. Check cost coverage to see what share of volume actually has a trustworthy fee estimate before relying on this post-step.
  • To compare cost-aware routing against a plain auth-rate baseline on live traffic before flipping the merchant flag, run it as an A/B test experiment arm (enable_multi_objective: true on one arm only).

Request

bash
curl --location "$BASE_URL/decide-gateway" \
  --header "$AUTH_HEADER" \
  --header "Content-Type: application/json" \
  --data '{
    "merchantId": "merchant_demo",
    "eligibleGatewayList": ["stripe", "adyen", "checkout"],
    "rankingAlgorithm": "SR_BASED_ROUTING",
    "eliminationEnabled": true,
    "enableMultiObjective": true,
    "paymentInfo": {
      "paymentId": "mo_001",
      "amount": 1000,
      "currency": "USD",
      "country": "US",
      "paymentType": "ORDER_PAYMENT",
      "metadata": null,
      "paymentMethodType": "CARD",
      "paymentMethod": "CREDIT",
      "authType": "THREE_DS",
      "cardIsin": "424242"
    }
  }'

Response: cost won

adyen is promoted over the SR head stripe because its expected value is higher at the configured margin; fallbacks are re-ordered by descending expected value (gateways without fee data follow, ordered by auth rate).

json
{
  "decided_gateway": "adyen",
  "fallback_gateways": ["stripe", "checkout"],
  "gateway_priority_map": {
    "stripe": 0.94,
    "adyen": 0.91,
    "checkout": 0.88
  },
  "filter_wise_gateways": null,
  "priority_logic_tag": null,
  "routing_approach": "SR_SELECTION_MULTI_OBJECTIVE",
  "gateway_before_evaluation": "stripe",
  "reset_approach": "NO_RESET",
  "routing_dimension": "ORDER_PAYMENT,CARD,CREDIT,UNKNOWN",
  "routing_dimension_level": "CARD_LEVEL",
  "is_scheduled_outage": false,
  "is_dynamic_mga_enabled": false,
  "gateway_mga_id_map": null,
  "is_rust_based_decider": true,
  "multi_objective_info": {
    "outcome": "COST_WON",
    "reason": "Promoted 'adyen' over 'stripe' on expected value — saves 80.00 bps for 3.00pp auth.",
    "srHead": { "psp": "stripe", "authRate": 0.94, "costBps": 180.0 },
    "chosen": { "psp": "adyen", "authRate": 0.91, "costBps": 100.0 },
    "costSavedBps": 80.0,
    "qualifiedCount": 3,
    "margin": 0.2,
    "evGapTop2": 0.00182
  }
}

Response: auth won

The post-step ran but the SR head was already the highest expected-value gateway, so nothing moves and routing_approach keeps its normal SR value. Note margin: 1 — the default applied when the merchant's success-rate config sets no margin.

json
{
  "decided_gateway": "adyen",
  "fallback_gateways": [
    "stripe",
    "checkout"
  ],
  "gateway_priority_map": {
    "adyen": 0.65,
    "checkout": 0.58,
    "stripe": 0.65
  },
  "filter_wise_gateways": null,
  "priority_logic_tag": null,
  "routing_approach": "SR_SELECTION_V3_ROUTING",
  "gateway_before_evaluation": "adyen",
  "priority_logic_output": {
    "isEnforcement": false,
    "gws": [
      "stripe",
      "adyen",
      "checkout"
    ],
    "priorityLogicTag": null,
    "gatewayReferenceIds": {},
    "primaryLogic": null,
    "fallbackLogic": null
  },
  "debit_routing_output": null,
  "reset_approach": "NO_RESET",
  "routing_dimension": "ORDER_PAYMENT, CARD, DEBIT, DEBIT",
  "routing_dimension_level": "CARD_LEVEL",
  "is_scheduled_outage": false,
  "is_dynamic_mga_enabled": false,
  "gateway_mga_id_map": null,
  "is_rust_based_decider": true,
  "latency": 3,
  "multi_objective_info": {
    "outcome": "AUTH_WON",
    "reason": "SR head retained — it is the highest expected-value PSP (3 ranked on EV).",
    "srHead": {
      "psp": "adyen",
      "authRate": 0.65,
      "costBps": 156.94736842105263
    },
    "chosen": {
      "psp": "adyen",
      "authRate": 0.65,
      "costBps": 156.94736842105263
    },
    "costSavedBps": null,
    "qualifiedCount": 3,
    "margin": 1,
    "evGapTop2": 0.013780000000000014
  }
}

multi_objective_info Fields

FieldTypeMeaning
outcomeCOST_WON | AUTH_WONTerminal outcome of the post-step. COST_WON means a higher-EV PSP was promoted above the SR head.
reasonstringHuman-readable explanation of the decision.
srHeadobject | nullThe PSP the SR scorer would have picked (psp, authRate, costBps).
chosenobject | nullThe PSP the post-step actually chose. Equals srHead when auth won.
costSavedBpsnumber | nullFee saved in bps when outcome == COST_WON (srHead.costBps − chosen.costBps).
qualifiedCountintegerNumber of PSPs that had cost data and were ranked on expected value.
marginnumberMerchant margin (fraction of ticket) applied for this transaction.
evGapTop2number | nullExpected-value gap between the top-two EV-ranked PSPs, as a fraction of ticket. Small values mean the decision was close. null when fewer than two PSPs had cost data.

The block is absent (null) when the post-step did not run at all — feature off, hedging active, or a non-SR routing flavour.