Miracle Docs
Configuration

Payment Routing

Payment routing determines which terminal processes each transaction. Configure rules to optimize acceptance rates, manage costs, and distribute traffic across your provider connections.


How Routing Works

When a payment is created, the routing engine evaluates the transaction in two phases:

  1. Phase 1 — Filter: Infrastructure filters narrow the pool to eligible terminals, then routing rules further refine the candidate set.
  2. Phase 2 — Score: If multiple candidates remain, the scoring engine picks the best terminal based on priority.

The full pipeline runs in this order:

Payment created --> Limit check --> Risk check --> 3DS decision --> Routing --> Attempt

If the selected terminal declines the transaction, cascading can retry with the next eligible terminal.


Infrastructure Filters

Before any rules are evaluated, the system automatically excludes terminals that cannot handle the transaction. These filters are not configurable — they enforce hard constraints:

FilterWhat it checks
DirectionTerminal direction must match (payin vs payout)
Terminal statusDisabled or test-only terminals excluded based on livemode
Payment methodTerminal must support the transaction's payment method
CurrencyBoth the terminal and channel must support the currency
3DS capabilityIf 3DS is required, terminal must support it
Terminal healthUnhealthy terminals are excluded

Routing Rules

Rules let you control which terminals handle specific types of transactions. Each rule has three components:

  • Conditions — criteria that a transaction must match
  • Actioninclude (add terminals to candidates) or exclude (remove terminals)
  • Candidates — the terminal(s) affected by this rule

Rules are evaluated in priority order (lower number = higher priority). Conditions within a single rule are AND-combined — all must match for the rule to apply.

Available Conditions

The routing engine supports 21 condition fields, grouped by category:

Transaction attributes

FieldDescriptionExample
amountTransaction amount in minor units1000--500000
currencyTransaction currencyEUR, USD
transaction_typeType of transactionpayment, refund
payment_method_typeType of payment methodcard, bank_transfer
is_recurringWhether the transaction is recurringtrue / false

Card attributes (from BIN lookup)

FieldDescriptionExample
brandCard networkvisa, mastercard
card_binCard BIN prefix411111--411199
card_bin_countryCountry of the card issuing bankDE, US
card_typeCard typecredit, debit, prepaid
card_levelCard level / tierclassic, gold, platinum
card_ownershipCard ownership typepersonal, corporate
issuer_nameName of the issuing bankDeutsche Bank, Chase

Payer attributes

FieldDescriptionExample
payer_countryPayer's countryFR, GB
payer_ip_countryCountry resolved from payer's IPNL, US
payer_email_domainDomain of the payer's emailgmail.com

Payer velocity (require aggregation)

FieldDescriptionExample
payer_success_countNumber of successful transactions by this payer> 5
payer_success_volumeTotal volume of successful transactions (minor units)> 100000
payer_decline_countNumber of declined transactions by this payer> 3

Temporal

FieldDescriptionExample
time_of_dayHour of the day (0--23, UTC)0--6 (night hours)
day_of_weekDay of the weeksaturday, sunday

Custom

FieldDescriptionExample
metadataCustom key-value pairs from transaction metadatametadata.channel = "mobile"

Include vs Exclude Rules

  • Exclude rules are evaluated first. All matching exclude rules are applied (not just the first match). Excluded terminals are removed from the pool.
  • Include rules are evaluated next in priority order. The first include rule whose conditions match AND whose candidates are still in the pool determines the final candidate set.
  • If no include rules exist, all remaining terminals (after infrastructure filters and exclude rules) are used as candidates.

Creating a Routing Rule

Portal: Navigate to Routing and select Create Rule.

  1. Name: Give the rule a descriptive name (e.g., "Route EUR Visa to Terminal A").
  2. Direction: Select payin or payout.
  3. Action: Choose include or exclude.
  4. Conditions: Add one or more conditions. All conditions must match for the rule to apply.
  5. Candidates: Select target terminal(s).
  6. Priority: Set the evaluation order (lower number = evaluated first).
  7. Status: Rules start as draft. Activate when ready.

Rule Lifecycle

StatusBehavior
draftNot evaluated. Use for preparation and review.
activeEvaluated at runtime against every matching transaction.
archivedNo longer evaluated. Kept for audit trail.

Rules support versioning — activating a new version of a rule automatically archives the previous version.


Cascading

Cascading and retry logic is a separate feature from routing rules. Routing rules determine which terminal is selected for an attempt. Cascading determines what happens after a decline — whether to retry and which terminal to try next. You do not configure cascading through routing rules.

When a terminal declines a transaction with a soft decline, cascading automatically retries with the next eligible terminal. The failed terminal is excluded from the candidate set, and the routing engine runs again to pick the next terminal.

When cascading applies

Cascading applies only to instant payments — synchronous card transactions that have not yet entered a user interaction flow. Once the payer is involved in a 3DS challenge, app confirmation, or external redirect, cascading is prohibited. Delayed payment methods (bank transfer, SEPA, ACH) are never eligible for automatic cascading.

After user interaction starts, the system will not cascade. If the payer has already been redirected for 3DS or another confirmation step, any subsequent failure is handled by the retry mechanism (which requires explicit payer action), not by cascading.

Configuration hierarchy

Cascade behavior is configured per merchant through the IntegrationProfile.cascadePolicy, not per channel. The system resolves the active policy using a three-level hierarchy:

LevelSourceDescription
1. MerchantIntegrationProfile.cascadePolicyPer-merchant override set by an operator
2. Tenant defaultTenantConfig.defaultCascadePolicyTenant-wide default, applies to all merchants without a merchant-level override
3. Platform built-inHardcoded defaultShips with the platform, used when neither merchant nor tenant policy exists

The first non-null policy in this chain is used at runtime.

CascadePolicy fields

FieldTypeDescription
maxAttemptsnumberMaximum cascade attempts per transaction (typically 2--5)
launchConditionsCascadeCondition[]Conditions that trigger cascading. Default: decline_category = 'soft'
blockConditionsCascadeCondition[]Conditions that prevent cascading (e.g., fraud_suspected, stolen_card)
terminalExclusion'failed_only' | 'all_attempted'Whether to exclude only the failed terminal or all previously attempted terminals
timeout.perAttemptnumber (ms)Maximum time per individual cascade attempt
timeout.totalnumber (ms)Maximum total cascade time before giving up (default 30s, platform max 120s)
uxConstraints.maxUserVisibleDelaynumber (ms)Stop cascading if the payer has already waited this long
uxConstraints.preserveRedirectbooleanDo not cascade if the current attempt involves a redirect or 3DS flow

Channel kill-switch

Each channel has a cascadingEnabled boolean. This is a per-channel toggle — when set to false, no cascading occurs for transactions on that channel regardless of the merchant's cascade policy. It does not replace the policy configuration; it only acts as an override to disable cascading on specific channels.

How cascading works

  1. The routing engine selects the primary terminal and sends the payment.
  2. The terminal responds with a decline. The system classifies the decline (soft/hard).
  3. The cascade engine checks the active policy: do launchConditions match? Do any blockConditions apply? Is maxAttempts exceeded? Is the total timeout budget remaining?
  4. If cascading is allowed, the failed terminal is excluded and the routing engine selects the next terminal from the remaining candidate set.
  5. The payment is re-submitted to the new terminal without any change to the payer's session.
  6. The process repeats until the payment succeeds, attempts are exhausted, or a block condition is hit.

The platform built-in default cascades on soft declines only, allows up to 3 attempts, and blocks on fraud-related error codes (fraud_suspected, stolen_card, invalid_card_number, card_lost). Operators can customize this per tenant or per merchant.


Fallback Behavior

If you have not configured any include rules for a given direction, the system falls back to using all infrastructure-filtered terminals. In this case, the terminal with the highest channel priority (lowest number) is selected.

This means you can start processing payments immediately after creating terminals and channels — routing rules are optional and additive.


Best Practices

Start simple. Begin without any routing rules and rely on channel priority. Add specific rules as your transaction volume and provider landscape grows.

Use cascading for higher acceptance. Configure a cascade policy on the merchant's integration profile so that soft declines from one provider automatically fall through to the next eligible terminal.

Watch for overlapping exclude rules. Because all matching exclude rules are applied, overly broad conditions can unintentionally remove terminals from the pool. Review the routing trace in transaction details to debug unexpected routing decisions.

  • Assign clear priorities to avoid ambiguity — no two include rules should have the same priority.
  • Use exclude rules sparingly for compliance (e.g., "never route country X to terminal Y").
  • Monitor acceptance rates per terminal in the dashboard to identify optimization opportunities.

On this page