The leading zero is why your signup form rejects real customers
A German number written 01512 3456789 nationally is +49 1512 3456789 internationally. Naive validation drops the wrong digits and rejects a genuine customer.
The most common cause of a valid phone number being rejected at signup is not fraud detection. It is a trunk prefix.
What a trunk prefix is
Most countries put a digit in front of a number when you dial it domestically. In Germany, the UK, Australia and much of Europe that digit is 0. It is a national dialling instruction, not part of the number, and it disappears when the number is written internationally.
Germany, national: 01512 3456789 Germany, international: +49 1512 3456789 Germany, E.164: +4915123456789
The 0 is gone in the last two. A form that concatenates a country code onto whatever the user typed produces +49 01512 3456789, which is not a valid number anywhere — and blames the customer for it.
It is not universal, which is the trap
The United States, Canada, India and much of Asia use no trunk prefix at all. Code written and tested against US numbers looks correct, ships, and then fails for every European customer. The bug is invisible in the market it was written in.
Do not write the rules yourself
Numbering plans change. Ranges are allocated and withdrawn, lengths vary by line type within one country, and a hand-rolled regex is out of date the moment it is written. libphonenumber exists precisely because this problem is much larger than it looks — use it, or use an API that does.
Validity is not the same as formatting
Correct formatting only says a number could exist. It does not say whether the range was ever allocated, whether it is mobile or VoIP, or whether it is worth trusting on a signup. Conflating the two is the second most common mistake after the leading zero.