Routing Rules
What a rule can pin down, what its match is worth, and where it cannot help.
A routing rule is one addition. It says that when a payment looks a certain way, one of your connections gets points, and those points only compete against the other connections sitting in the same priority tier. That is the whole mechanism.
A rule is not an ordered list of providers, and it does not build a fallback chain. The chain is the ranked candidate list described in Orchestration, and a rule can only change who goes first inside one tier of it.
Growth and above, live only
Routing rules are a paid feature. On Pay as you go the Orchestration, Rules page is replaced by an upgrade prompt, and the whole Orchestration section is live only by route middleware. Everything on this page assumes a live key and a Growth, Scale or Enterprise plan.
What the router reads
A rule has four conditions, one target, and one number of its own. Every field is optional except the target.
channelstringoptionalcurrencystringoptionalmin_amount / max_amountamountoptionalcountry_codestringoptionalprovider_idstringrequiredpriorityintegerrequireddefault : 0is_activebooleanoptionaldefault : trueEvery active rule of yours is evaluated on every live payment. There is no ordering to maintain and no first-match-wins: rules that match all contribute, each to its own target.
What a match is worth
The score is built from the number of conditions the rule actually pins down. A vague rule is worth less than a precise one, on purpose.
| Part of the match | Points |
|---|---|
| The rule matched at all | 1000 |
| It pins a channel | 500 |
| It pins a currency | 500 |
| It pins an amount range, either side | 500 |
| It pins a country | 500 |
The rule's own priority | Its value, added as is |
Take an account with CinetPay and Flutterwave both connected, both at priority 0, both able to
carry cm.mtn in XAF, and one rule pinning cm.mtn and XAF to CinetPay with a rule priority of
0. CinetPay scores 1000 for the match plus 500 for the channel plus 500 for the currency, so
2000. Flutterwave has no rule, and on a fresh account it picks up at most the least-cost boost and
the telemetry boost.
Routing decision · cm.mtn · 12 000 XAF
One rule, two connections in the same tier. 2000 against 250 is not close.
- 1

cinetpayaccepted1.1 spriority 0 · score 2000rule +2000 - 2

flutterwavenever calledpriority 0 · score 250least cost +200success 91 % +50
That gap is the point. A rule is worth between 1000 and 3000 while cost is worth 200 and live success rate is worth 50 at best, so once a rule matches, nothing else in the score can outvote it. Write rules for cases where you know better than the numbers, and leave the rest to the numbers.
Two rules on the same connection
Only the highest-scoring rule survives per target. If a broad rule pinning just cm.mtn and a
narrow one pinning cm.mtn, XAF and an amount ceiling both point at CinetPay, CinetPay is scored
once, at 2500, and the broad rule contributes nothing extra. Stacking rules on one connection never
compounds.
Two rules on different connections
Both count, each on its own target, and the higher total goes first. This is how you split traffic by amount: one rule per bracket, each pointing at a different connection.
Where a rule cannot help
Three things silently make a rule inert, and all three are worth checking before you conclude the engine ignored you.
A rule never crosses a priority tier. Candidates are grouped by the priority on your
connection and the top group is exhausted before the next is touched. A 3000-point rule pointing at
a connection in a lower tier changes nothing at all: the higher tier is still tried first, and if
one of them accepts, your rule's target is never called. If a rule looks ignored, look at the
connection's priority first.
The target has to be a connection you hold. The form only lets you pick from providers already connected to your account, active, in live mode. A connection you later pause takes its rules out of play with it.
The channel has to be a slug the router actually sees. By the time candidates are ranked, the
channel is a resolved operator slug. A rule written against a product word like mobile_money,
bank_transfer or mobile matches nothing, because no payment is ever routed on those strings.
Leave the country condition empty
The router derives the country from the channel, not from the payer: cm.mtn gives it cm, in
lowercase, and it compares that against the rule's stored country_code, which the Dashboard
writes in uppercase. CM and cm are not equal in Postgres, so a rule that pins a country
matches nothing today. You lose nothing by leaving it empty, because the channel already carries
the country on every operator rail: a rule on cm.mtn is already a rule about Cameroon.
A rule that has an effect
The shape worth copying is narrow on the channel, explicit on the currency, and pointed at a connection that already sits in the tier where the decision happens.
Say MTN Cameroon is your biggest rail, you have three connections that can carry it, and one of them gives you the best acceptance for amounts under 100 000 XAF. Put all three at the same priority so they compete, then write one rule.
| Field | Value |
|---|---|
channel | cm.mtn |
currency | XAF |
max_amount | 100000 |
provider_id | your preferred connection |
priority | 0 |
That rule scores 2500. Above 100 000 XAF it stops matching, the boost disappears, and the three connections fall back to competing on cost and on live success rate, which is usually what you want for the amounts you care most about.
Amount bounds are entered in major units, the same units as the payment. 100000 means 100 000
XAF, not 1 000 XAF.
The simulator on the Rules page
The Rules page has a simulator that takes a channel, a currency and an amount, and shows which of your rules match. It is useful for one thing: checking that the conditions you typed select the rules you meant.
It is not the router. It reads your rules directly and does not reproduce the connection priority tiers, the least-cost boost, the live success rate boost, or the circuit breaker, and it compares the country condition case-insensitively where the engine does not. A provider can come first in the simulator and never be called on a real payment. For the real answer, send a live payment and read the routing log.
Fields the form stores but the router ignores
The rule form carries more than the engine consumes. These are written to your rule, visible when you reopen it, and read by nothing on the payment path.
| Field | What happens |
|---|---|
fallback_provider_id | Stored. The fallback order comes from the candidate list, never from a rule |
weight | Stored. Traffic splitting uses the weight on the connection, not on the rule |
| Time windows | Stored, never evaluated |
| Customer segments | Stored, never evaluated |
| Metadata filters | Stored, never evaluated |
| Frequency caps | Stored, never evaluated |
Everything the router reads is in the first table on this page. If a behaviour you expect is not explained by those fields, it is not coming from your rules.
Related pages
- Payment OrchestrationThe filters, the priority tiers, and the three additions of the score.
- Waterfall & FallbackWhat walks down the list, and what takes a route out of rotation.
- ProvidersPriority, weight and negotiated rates, on the connection itself.
- Routing LogWhich rule scored which connection, on a payment that already happened.