Quickstart
Make the routing visible on a live payment, then move one connection and watch it move.
There is nothing to switch on. Orchestration has been ranking your connections since your first live payment, and no request field starts it or stops it. So this quickstart does not add a call to your integration. It makes the ranking visible, then changes it once so you can watch it move.
Five steps. All of them in live mode, and the first one explains why.
Sandbox does not route
A sandbox payment goes to one synthetic provider and stops there. No candidate list is built, no decision is recorded, and Konsole's routing log refuses a sandbox key outright. There is no way to rehearse a routing decision without real money, so use the smallest amount your operator accepts and pay yourself.
1. Connect a second provider
One connection has nothing to fall back to. The engine still runs, still ranks, and still records a decision, but the list is one line long and a failure ends the payment.
Add a second in the dashboard under Orchestration, Providers. Both sides have to be live: the provider itself, and your connection to it. The router drops an inactive row on either side before it ranks anything, so a half-finished connection is invisible rather than last.
2. Give them an order
Every connection carries two numbers, both on the provider page under Routing configuration.
| Field | What it decides | Default |
|---|---|---|
priority | The order of the whole list. Higher first | 0 |
weight (%) | Which of two connections goes first when they tie on priority and on score | 100 |
Priority is absolute. A connection in a lower tier is never tried before every connection above it has been tried and failed, whatever it costs and whatever rule matched it.
Weight is a tie-break of a tie-break
orderTierByWeight() only runs on candidates that already share a priority and a tie-break
score, and it only decides which one goes first. Two connections on the same priority with
different scores never split traffic. That said, a fresh account has no negotiated rates and no
rules, so every score is 0 and weight really is what decides.
Set one connection to 10 and leave the other at 0. That gives you two tiers, which is the
smallest setup where the next steps show something.
3. Send a live payment
A payment is two calls, and this is the part most integrations get wrong: the first call does not route. It creates the transaction, and it accepts no channel and no provider.
https://api.wajub.com/paymentsPass an amount, a currency, and one way to identify the payer among email, phone, customer_id
and customer.
curl https://api.wajub.com/payments \
-H "Authorization: sk.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
-H "Content-Type: application/json" \
-d '{
"amount": 500,
"currency": "XAF",
"phone": "+237670000000",
"description": "Watching the router work"
}'The second call is the one that routes. It names a channel, and everything in Orchestration happens inside it.
https://api.wajub.com/payments/{id}curl https://api.wajub.com/payments/trx.PVrU8x2k \
-H "Authorization: sk.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
-H "Content-Type: application/json" \
-d '{
"channel": "cm.mobile",
"data": { "phone": "+237670000000" }
}'cm.mobile never reaches the router. resolveOperatorChannel() reads the number, works out the
operator, and hands the router cm.mtn. Candidates are then filtered against that resolved channel,
so a connection that declares cm.orange and not cm.mtn is out before ranking starts.
4. Read the decision
Open the payment in the dashboard. Under the timeline sits Routing decision, and "View routing details" opens the list the router built, in the order it built it.
Routing decision · cm.mtn · 500 XAF
Two connections, two tiers. The first one answered, so the second was never called.
- 1

cinetpayaccepted1.2 spriority 10 · score 0 - 2

flutterwavenever calledpriority 0 · score 0
Both scores are 0, and that is the expected reading on a fresh account. The score is only rule
boosts, a least-cost boost and a telemetry boost; with no rules written, no negotiated rates entered
and no recent history on this channel, there is nothing to add. Priority is doing all the work,
which is exactly what you set up in step 2.
The same list lives in the routing log, one row per decision rather than one per payment. That page is live only, by route middleware, for the reason in the first callout.
5. Move one, and watch it move
Swap the two priorities: the connection that was on 0 goes to 10, the other drops to 0. Send a
second payment, identical to the first.
The ladder comes back in the new order. Nothing in your code changed, no deploy happened, and the payment request is byte for byte the one you sent five minutes ago. That is the whole point of the feature, and it is worth doing once with your own eyes before you trust it in production.
What the API will not tell you
PaymentResource exposes no provider field. GET /payments/{id} returns the channel that was
charged, never the connection that carried it, and there is no merchant endpoint that returns
priority, weight or a candidate list. Routing is visible in the dashboard and in Konsole, and
nowhere else.
A 422 on channel means the list came back empty
When no connection survives the filters, the payment answers
422 No eligible payment provider found for this transaction. on the channel key and the
transaction goes back to pending. It is an account configuration problem, not a payer problem:
the channel, the currency or the circuit breaker removed every candidate before ranking.
Related pages
- Payment OrchestrationThe six filters, the priority tiers and the three additions of the score.
- Routing RulesBoost a connection for a country, channel, currency or amount range.
- Waterfall & FallbackWhat walks down the list, and what stops it for good.
- Accept a paymentThe full two-call flow, hosted page included.