Global phone number validation API

Validate every phone number before you send the SMS.

Format, line type and country detection for every calling code on earth — in under 100ms. Catch VoIP, premium-rate and impossible numbers before they burn your OTP budget. 100 free checks every month.

No credit card. No sales call. Live key in under a minute.

POST /api/public/v1/verify
curl -X POST https://fishymails.com/api/public/v1/verify \
  -H "Authorization: Bearer fm_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"kind":"phone","value":"+31 6 12345678"}'

{
  "kind": "phone",
  "status": "valid",
  "score": 95,
  "checks": {
    "country": "NL",
    "type": "MOBILE",
    "e164": "+31612345678",
    "formatted_international": "+31 6 12345678",
    "is_valid": true
  },
  "latency_ms": 41
}

Protecting OTP flows and CRM data for teams like:

Second LegacyHELLO LabsLeadFind

The three things bad data is costing you right now

Undeliverable numbers silently fail

Wrong length, missing country code, a typo'd digit — the SMS never lands, the user never onboards, and nobody finds out until support gets the ticket.

Full numbering-plan validation catches malformed numbers at the form, while the user is still on the page.

SMS pumping drains your OTP budget

Fraud rings push signups through premium-rate and VoIP ranges and take a cut of every message you send. Bills spike overnight.

Line-type detection flags VoIP, premium-rate and shared-cost numbers as risky before a single message is sent.

Dirty CRM data kills your sales team

Reps dial dead numbers, dashboards count contacts that can never be reached, and routing rules fire on the wrong country.

Normalised E.164 output plus country and line type gives every record one clean, dial-ready format.

Live in three steps

  1. 1

    Get your API key

    Sign up free, copy your key from the dashboard. No credit card, no sales call.

  2. 2

    Send a request

    POST kind: 'phone' with the raw number. Add an optional country hint for local formats.

  3. 3

    Get results instantly

    E.164 format, country, line type, validity and a 0-100 score come back in one JSON body.

request / response
// Mix phones with emails and IPs in one bulk call
await fetch("https://fishymails.com/api/public/v1/verify/bulk", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FISHYMAILS_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    items: [
      { kind: "phone", value: "0612345678", country: "NL" },
      { kind: "phone", value: "+1 900 555 0199" },
      { kind: "email", value: "jane@acme.io" },
    ],
  }),
});

{
  "count": 3,
  "results": [
    { "value": "0612345678",     "status": "valid", "score": 95 },
    { "value": "+1 900 555 0199","status": "risky", "score": 40 },
    { "value": "jane@acme.io",   "status": "valid", "score": 95 }
  ]
}

Built for production, priced for prototypes

Every country, every format

Full international numbering-plan coverage with optional country hints for local-format input.

Line type detection

Mobile, fixed line, VoIP, toll-free, premium rate and shared cost — returned explicitly on every check.

Under 100ms

Validation runs in-process with no third-party hop, fast enough to sit inline on a signup form.

E.164 normalisation

Every valid number comes back in canonical E.164 plus a human-readable international format.

Mixed bulk batches

Send phones, emails and IPs together, up to 100 items per call, processed in parallel.

Predictable pricing

One credit per number. 100 free every month, then $29 for 1,000. Cancel any time.

100 free checks every month. No credit card required.

Paid plans start at $29/month for 1,000 checks and scale to 250,000. Annual billing gives you two months free. No seat fees, no minimum contract, cancel whenever.

Questions developers actually ask

Cut your SMS waste starting with the next signup.

Set up in 5 minutes. Your first 100 checks are free.