# Account security and takeover risk

> Check the phone number or e-mail address a user adds or changes on an account, and step up verification when the signals suggest takeover risk.

Canonical: https://mobilevalidate.com/use-cases/account-security · Last updated: 2026-09-25

![An account's two-factor phone number is changed to a VoIP number; the change is flagged and an extra verification step is required.](https://mobilevalidate.com/images/account-takeover-contact-change-risk.svg)

*When a 2FA number changes to a riskier line, ask for an extra verification step.*


Account takeovers often start with a change of contact details. The attacker adds their own phone number for two-factor codes or swaps the recovery e-mail. Checking the new number and address when they change gives your security logic facts to weigh: the line type, whether the mailbox exists and, where enabled, spam reputation. Risky changes can get an extra verification step before they take effect.

## Where does contact-detail risk show up?

Attackers who get into an account usually try to keep it. That means changing where codes and reset links go. Warning signs include:

- **A new 2FA number that is a VoIP line.** Legitimate users have VoIP numbers too, but attackers often use them because they're cheap and easy to get. The [carrier lookup](/services/carrier-lookup) reports `line_type`. See [VoIP number](/glossary/voip-number).
- **A recovery e-mail with no mailbox behind it.** An address at a major webmail provider that doesn't exist can't receive recovery mail. That points to a typo or a throwaway. The [e-mail mailbox check](/services/email-verification) answers this.
- **A number with fraud or spam reports.** Where [spam reputation](/services/spam-reputation) is enabled (limited access; US, CA and DE numbers), reasons such as `reason_unassigned` or `reason_regulator` are worth weighing.
- **A change of country.** The carrier lookup's `country` can differ from the account's usual country.

Each signal is weak on its own. A combination, together with your own session data such as a new device or an unusual location, is what should trigger a step-up.

## How does the workflow look?

1. The user submits a new phone number or e-mail address.
2. Call `POST /v1/lookup` with the new identifiers and `checks: ["carrier", "spam", "email"]`. Leave out `spam` if it isn't enabled for your account.
3. Combine the results with your session risk and apply the table below.
4. For a step-up, confirm through the old number or e-mail, or hold the change for a cooling-off period.
5. Log the decision with `checked_at`. Keep the raw response only as long as you need it.

The request is small (one number, one address), so it fits in the synchronous part of a settings change.

## What should you do with each result?

| Signals | Suggested action |
|---|---|
| Mobile line, mailbox exists, no reports | Allow the change |
| `line_type: voip` and the session is otherwise normal | Allow, and notify the old contact details |
| `line_type: voip` and a new device or location | Step up: confirm through the old number or e-mail |
| Mailbox `registered: false` | Ask the user to check the address; don't make it the recovery e-mail |
| Spam `risk_level: high` or `reason_unassigned: true` | Step up, and hold the change for review |
| Checks `unknown` | Decide on your other signals; unknown is not negative and is not charged |

## How much does it cost?

Each check on each identifier is billed only when the answer is conclusive. You're not charged for inconclusive results (unknown, unsupported country, timeout, invalid, duplicate). Contact-detail changes are rare events, so this use case usually costs very little: a few real-time checks per change. Spam reputation bills every level, including `no_reports`, and is free outside the US, Canada and Germany. See [pricing](/pricing) for current rates.

## Example request

Test mode, with a number that has no carrier data and no reports, and an address with an existing mailbox:

```bash
curl https://api.mobilevalidate.com/v1/lookup \
  -H "Authorization: Bearer $MOBILEVALIDATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"numbers": ["+447700900002"], "emails": ["registered@test.mobilevalidate.com"], "checks": ["carrier", "spam", "email"]}'
```

Response (excerpt, test mode: the `checks` of the phone row, then of the e-mail row):

```json
[
  {
    "network.carrier": {
      "service": "network.carrier", "status": "unknown", "registered": null, "attributes": null,
      "confidence": null, "confidence_score": null, "checked_at": null,
      "cached": false, "age_seconds": null, "billed": false, "reason": "NO_DATA", "poll_after_ms": null
    },
    "number.spam": {
      "service": "number.spam", "status": "completed", "registered": true,
      "attributes": {
        "risk_level": "no_reports", "risk_score": 0, "reason_regulator": false, "reason_government": false,
        "reason_community": false, "reason_unassigned": false, "voip_range": false, "sources": 0
      },
      "confidence": "high", "confidence_score": 0.99, "checked_at": "2026-09-25T14:28:26.024Z",
      "cached": false, "age_seconds": 0, "billed": false, "reason": null, "poll_after_ms": null
    }
  },
  {
    "email.valid": {
      "service": "email.valid", "status": "completed", "registered": true, "attributes": null,
      "confidence": "high", "confidence_score": 0.99, "checked_at": "2026-09-25T14:28:26.024Z",
      "cached": false, "age_seconds": 0, "billed": false, "reason": null, "poll_after_ms": null
    }
  }
]
```

The carrier answer is `unknown` (`NO_DATA`) and free. The rest of the decision rests on the spam level, the mailbox result and your own session signals.

## What limits and rules apply?

The usual lookup limits apply: up to 100 identifiers and 20 checks per request, rate limits per key and a daily cap per account. Requests that look like sequential number ranges or generated e-mail lists are rejected. E-mail checks return only yes, no or unknown, never names or profiles.

Check only the contact details your users give you for their own accounts, and say in your privacy notice that you do so for security. Results support a step-up decision. They are not identity proof, and on their own they shouldn't lock people out of their accounts. People can object through the [opt-out form](/opt-out).

## Frequently asked questions

### When should I run these checks?

At moments when attackers change contact details: a new phone number for two-factor authentication, a changed recovery e-mail, a password reset to a new destination or a first login from a new device.

### Should I lock the account when a signal looks risky?

Usually not. Ask for an extra verification step instead, such as confirming on the old number or e-mail, a delay before the change takes effect, or a support review. Locking hurts genuine users who just changed phones.

### Does the mailbox check read or send e-mail?

No. It only answers whether the mailbox exists, for major webmail providers. Nothing is sent to the address and no mailbox content is accessed.

### Can I use these checks as identity verification?

No. They are risk signals about a number or an address, not proof of who someone is, and must not be used as KYC or for credit, employment, housing or insurance decisions.

### Is spam reputation part of this?

It can be, where it is enabled. Spam reputation is in limited access (internal customers only) and covers US, Canadian and German numbers.
