Phone number formats
How Wajub reads a Mobile Money number, country by country, and what it rejects.
Mobile Money is identified by phone number everywhere Wajub touches it: a customer paying in, a payout leaving your balance, a marketplace settling a seller. Get the format wrong and the payment fails before the customer ever sees a prompt, which makes this the most common integration error we see.
Send E.164
Wajub expects the international form: a +, the country dialling code, then the subscriber number.
No spaces, no dashes, no parentheses, no leading zero from the national format.
+[country code][subscriber number]
+237670000000 Cameroon, MTN
+221770000000 Senegal, Orange
+254700000000 Kenya, SafaricomA number that arrives without its country code is not automatically refused. Wajub parses it with
libphonenumber, and when the call carries a country to anchor it on, a channel like cm.mtn is
enough, a local number such as 670000000 is read as +237670000000. Without that anchor there is
nothing to guess from, and the number comes back as a 422.
Send E.164 anyway
Relying on the fallback means relying on your own channel being right. Normalise on your side,
at the point where the customer types the number, and you remove a whole class of failure from
every call that follows.
Every country Wajub reaches
Sixteen countries, each with its dialling code and the operators Wajub knows there.
| Country | Dialling code | Operators |
|---|---|---|
+237 | MTN MoMo, Orange Money, Express Union, Yoomee Money | |
+225 | MTN MoMo, Orange Money, Moov Money, Wave, Green Money | |
+221 | Orange Money, Free Money | |
+229 | MTN MoMo, Moov Money, Glo | |
+226 | Orange Money, Moov Money | |
+234 | MTN MoMo, Orange Money | |
+233 | MTN MoMo, Vodafone Cash, Airtel Money, AirtelTigo Money | |
+254 | M-Pesa, M-Pesa Till, Airtel Till, Equitel, T-Kash | |
+256 | MTN MoMo, Airtel Money | |
+250 | MTN MoMo, Airtel Money | |
+255 | Airtel Money, Tigo Pesa, Vodafone Cash, HaloPesa | |
+243 | Airtel Money, Orange Money, Vodacom M-Pesa, Express Union | |
+241 | Airtel Money, Express Union | |
+235 | Express Union | |
+236 | Express Union | |
+242 | Express Union |
How the operator is identified
This is where production and sandbox genuinely differ, and the difference matters.
In production, Wajub asks libphonenumber's carrier database who actually owns the number. That database is maintained by Google and tracks real allocations, so it survives number portability and new ranges without anyone updating a table here. The carrier name it returns is mapped to an operator: MTN, Orange, Airtel, Moov, Wave, Safaricom, Vodacom, Free, Nexttel, Camtel, Yoomee and Expresso are recognised. A carrier outside that list is treated as no supported operator.
In sandbox, no real number exists to look up, so Wajub matches the prefixes below instead. They are synthetic: they exist to make test outcomes deterministic, not to describe how real numbers are allocated.
Do not build a prefix table of your own
The prefixes below are the sandbox's. Copying them into your code means reimplementing operator detection with data that is wrong in production, and stale the day a range is reassigned. Send the number and let Wajub resolve it.
| Country and operator | Sandbox prefix | Channel |
|---|---|---|
+23767… | cm.mtn | |
+23769… | cm.orange | |
+23768… | cm.eu | |
+23766… | cm.yoomee | |
+22505… | ci.mtn | |
+22507… | ci.orange | |
+22501… | ci.moov | |
+22503… | ci.wave | |
+22509… | ci.green | |
+22177… | sn.orange | |
+22176… | sn.free | |
+22990… | bj.mtn | |
+22991… | bj.moov | |
+22997… | bj.glo | |
+22670… | bf.orange | |
+22671… | bf.moov | |
+2348… | ng.mtn | |
+2347… | ng.orange | |
+23324… | gh.mtn | |
+23320… | gh.vodafone | |
+23326… | gh.airtel | |
+23327… | gh.airteltigo | |
+25470… | ke.mpesa | |
+25471… | ke.mpesa_till | |
+25473… | ke.airtel_till | |
+25476… | ke.equitel | |
+25477… | ke.tkash | |
+25677… | ug.mtn | |
+25675… | ug.airtel | |
+25078… | rw.mtn | |
+25073… | rw.airtel | |
+25567… | tz.airtel | |
+25565… | tz.tigo | |
+25574… | tz.vodafone | |
+25562… | tz.halopesa | |
+24399… | cd.airtel | |
+24389… | cd.orange | |
+24381… | cd.vodacom | |
+24382… | cd.eu | |
+2410… | ga.airtel | |
+2411… | ga.eu | |
+23566… | td.eu | |
+23670… | cf.eu | |
+24205… | cg.eu |
Letting Wajub pick the channel
Send a phone number with no channel and Wajub resolves the operator itself, then routes to the
best available provider for it. This is the normal case, and the one to prefer.
Name a channel only when you want to force one operator, on the charge call of a Direct API
integration. If the number and the channel disagree, the call is refused rather than silently
rerouted.
What comes back when it is wrong
| Response | Cause | Fix |
|---|---|---|
422 on phone | No +, no country code, and nothing to anchor the number on | Normalise to E.164 before you send |
422 on channel | The channel names an operator that does not serve that country | Check the country's operators above |
422, number and channel disagree | The number belongs to another operator than the one you named | Drop channel and let Wajub resolve it |
failed with invalid_phone | The number parsed but no carrier owns it | Ask the customer to confirm their number |
The first three are refusals at creation, so nothing is charged and nothing appears in your Dashboard. The last one is a real payment that reached an operator and came back, and it shows up in the failure reasons catalogue.
Related pages
- Payment methods & channelsEvery operator, its channel, and where it works.
- Sandbox test numbersThe suffixes that drive each outcome in test mode.
- Failure reasonsThe full catalogue, including invalid_phone.
- TransfersThe same format, used as a payout destination.
- SyncThe same format, used to settle a marketplace seller.