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:
- Phase 1 — Filter: Infrastructure filters narrow the pool to eligible terminals, then routing rules further refine the candidate set.
- 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 --> AttemptIf 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:
| Filter | What it checks |
|---|---|
| Direction | Terminal direction must match (payin vs payout) |
| Terminal status | Disabled or test-only terminals excluded based on livemode |
| Payment method | Terminal must support the transaction's payment method |
| Currency | Both the terminal and channel must support the currency |
| 3DS capability | If 3DS is required, terminal must support it |
| Terminal health | Unhealthy 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
- Action —
include(add terminals to candidates) orexclude(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
| Field | Description | Example |
|---|---|---|
amount | Transaction amount in minor units | 1000--500000 |
currency | Transaction currency | EUR, USD |
transaction_type | Type of transaction | payment, refund |
payment_method_type | Type of payment method | card, bank_transfer |
is_recurring | Whether the transaction is recurring | true / false |
Card attributes (from BIN lookup)
| Field | Description | Example |
|---|---|---|
brand | Card network | visa, mastercard |
card_bin | Card BIN prefix | 411111--411199 |
card_bin_country | Country of the card issuing bank | DE, US |
card_type | Card type | credit, debit, prepaid |
card_level | Card level / tier | classic, gold, platinum |
card_ownership | Card ownership type | personal, corporate |
issuer_name | Name of the issuing bank | Deutsche Bank, Chase |
Payer attributes
| Field | Description | Example |
|---|---|---|
payer_country | Payer's country | FR, GB |
payer_ip_country | Country resolved from payer's IP | NL, US |
payer_email_domain | Domain of the payer's email | gmail.com |
Payer velocity (require aggregation)
| Field | Description | Example |
|---|---|---|
payer_success_count | Number of successful transactions by this payer | > 5 |
payer_success_volume | Total volume of successful transactions (minor units) | > 100000 |
payer_decline_count | Number of declined transactions by this payer | > 3 |
Temporal
| Field | Description | Example |
|---|---|---|
time_of_day | Hour of the day (0--23, UTC) | 0--6 (night hours) |
day_of_week | Day of the week | saturday, sunday |
Custom
| Field | Description | Example |
|---|---|---|
metadata | Custom key-value pairs from transaction metadata | metadata.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.
- Name: Give the rule a descriptive name (e.g., "Route EUR Visa to Terminal A").
- Direction: Select
payinorpayout. - Action: Choose
includeorexclude. - Conditions: Add one or more conditions. All conditions must match for the rule to apply.
- Candidates: Select target terminal(s).
- Priority: Set the evaluation order (lower number = evaluated first).
- Status: Rules start as
draft. Activate when ready.
Rule Lifecycle
| Status | Behavior |
|---|---|
draft | Not evaluated. Use for preparation and review. |
active | Evaluated at runtime against every matching transaction. |
archived | No 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:
| Level | Source | Description |
|---|---|---|
| 1. Merchant | IntegrationProfile.cascadePolicy | Per-merchant override set by an operator |
| 2. Tenant default | TenantConfig.defaultCascadePolicy | Tenant-wide default, applies to all merchants without a merchant-level override |
| 3. Platform built-in | Hardcoded default | Ships 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
| Field | Type | Description |
|---|---|---|
maxAttempts | number | Maximum cascade attempts per transaction (typically 2--5) |
launchConditions | CascadeCondition[] | Conditions that trigger cascading. Default: decline_category = 'soft' |
blockConditions | CascadeCondition[] | 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.perAttempt | number (ms) | Maximum time per individual cascade attempt |
timeout.total | number (ms) | Maximum total cascade time before giving up (default 30s, platform max 120s) |
uxConstraints.maxUserVisibleDelay | number (ms) | Stop cascading if the payer has already waited this long |
uxConstraints.preserveRedirect | boolean | Do 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
- The routing engine selects the primary terminal and sends the payment.
- The terminal responds with a decline. The system classifies the decline (soft/hard).
- The cascade engine checks the active policy: do
launchConditionsmatch? Do anyblockConditionsapply? IsmaxAttemptsexceeded? Is the total timeout budget remaining? - If cascading is allowed, the failed terminal is excluded and the routing engine selects the next terminal from the remaining candidate set.
- The payment is re-submitted to the new terminal without any change to the payer's session.
- 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.