Skip to content

Risk & compliance

Prove control of a phone or email

Send a six-digit code by SMS or email and record a verified code as a check with its own reference_id and audit trail.

What it does

OTP Ownership, in detail.

SMS and email

SMS to local (0803…) or E.164 numbers and email to any address; WhatsApp is not yet live.

Fixed limits

Ten-minute expiry, five attempts, a 30-second resend cooldown and five sends per destination per hour, each with its own error code.

Device and IP signals

Pass client_ip and user_agent to flag VPN or hosting IPs, Tor, headless browsers, disposable emails and virtual numbers.

Billed only on success

Only a verified code is billed, never a wrong one.

Templates in five languages

Set template_locale to en, ha, yo, ig or pcm.

How it works

From request to decision.

  1. 1

    POST /v1/otp/send

    Choose the channel and destination; you receive an otp_ id, masked destination, expiry, retry_after and max_attempts.

  2. 2

    The customer enters the code

    Show the masked destination and a resend button that respects retry_after.

  3. 3

    POST /v1/otp/verify

    Send the id and code to receive a verification, or attempts_remaining on failure.

Routing and providers

SMS goes through Speedmap’s SMS partner and email through Speedmap’s mailer. Destinations and codes are stored hashed and masked.

Use it

One request. One normalized response.

Call POST /v1/otp/verify through @speedmap/node, speedmap for Python.

Request
curl -X POST http://localhost:4000/v1/otp/verify \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "id": "otp_1a5dabfcfba052dd",
  "code": "123456"
}'
Response · 200 OK
{
  "reference_id": "spm_33b168aac3f7166171247ed8",
  "object": "verification",
  "product": "otp",
  "method": "otp_sms",
  "status": "verified",
  "match": true,
  "mode": "sandbox",
  "summary": {
    "otp_id": "otp_1a5dabfcfba052dd",
    "channel": "sms",
    "destination_masked": "**********4567",
    "verified": true,
    "attempts": 1,
    "purpose": "account opening",
    "sent_at": "2026-10-20T12:53:14.965Z",
    "verified_at": "2026-10-20T12:53:15.054Z",
    "risk_signals": {
      "score": 0,
      "level": "low",
      "factors": [],
      "phone": {
        "network": "MTN",
        "is_virtual": false,
        "nigerian": true
      }
    }
  },
  "consent": {
    "mechanism": "subject_otp",
    "consent_id": null
  }
}

Use cases

Where Nigerian teams use it.

Signup

Prove the phone before the NIN or BVN check, binding the verified identity to a phone the customer holds.

Payout destination changes

Require an OTP to the registered number before a settlement account changes.

Hosted pages

The same OTP engine confirms the subject on Speedmap-hosted consent and verification pages.

Candidate onboarding

Confirm a candidate’s email before sending a document capture link.

Part of:Lending

What you get back

The fields you will read.

  • summary.verified

    Meaning
    true on a correct code
  • summary.channel / destination_masked

    Meaning
    Where the code went
  • summary.attempts

    Meaning
    How many tries it took
  • summary.risk_signals

    Meaning
    Score, level and factors from the destination and any client_ip and user_agent hints
  • error.code

    Meaning
    otp_invalid, otp_expired, otp_too_many_attempts, otp_already_used, otp_resend_too_soon, otp_destination_limited

Assertion tier

Identical on every tier: the destination is always masked.

Full tier

Adds data: the full device and IP risk assessment (factor weights and details). Destinations stay masked.

Pricing

Billed per live check on the Scale up plan. Failed calls and idempotent retries are never billed.

FAQ

OTP Ownership questions.

Need more detail? Read the documentation or talk to our team.

Does an OTP prove identity?
No. It proves possession at that moment; add Phone Identity, Fraud Signals or a NIN or BVN check to know who holds it.
Can I use my own SMS sender name?
Sender IDs are configured per workspace during the compliance review.

Start verifying in minutes. Go live when you’re ready.

Create your account in under a minute and explore the full dashboard. We switch your workspace live after a short compliance review.