One-time codes

Send a code by email or SMS, check what the user typed, and tune the risk checks.

A one-time code proves someone owns an email address or a phone number. You ask Notix to send a code, the user types it into your app, and you ask Notix to check it. Notix keeps only a keyed hash of each code.

Send and check a code

  1. Send the code

    Call Send a one-time code with the address. Keep the id it returns.

    curl -X POST https://app.usenotix.dev/api/v1/verify/send \
      -H "Authorization: Bearer $NOTIX_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "to": "maria@example.com",
        "appName": "Acme"
      }'
    
  2. Check what the user typed

    Call Check a one-time code with the id and the code. The answer says whether it matched and how many tries are left.

    curl -X POST https://app.usenotix.dev/api/v1/verify/check \
      -H "Authorization: Bearer $NOTIX_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "id": "ver_8f3k2", "code": "482913" }'
    

Send a code by SMS

Pass "channel": "sms" and a phone number with its country code. For SMS, appName is required and may not contain a link. SMS codes are paid from your wallet, like any text, and need no paid plan.

{
  "to": "+2348012345678",
  "channel": "sms",
  "appName": "Acme"
}

The default text is "Acme: your code is 482913. It expires in 10 minutes." With your own approved sender ID you can change it. See Sender IDs.

Options and limits

SettingDefaultAllowed
codeLength6 digits4 to 8
expiresIn600 seconds60 to 1800
Wrong tries per code5Fixed
Codes per recipient5 every 10 minutesFixed, with 30 seconds between sends

For email codes you can also set from, subject and a templateId whose subject and body use {{code}}, {{appName}} and {{expiresMinutes}}.

Risk checks

Every request is scored before anything is sent. The answer carries a risk object with the score, the level (Low, Medium or High) and each signal that fired, such as a disposable email domain. Pass clientIp, the address your user made the request from, so the per address signal can count. Notix stores only a keyed hash of it.

A refused request answers 422 RISK_REFUSED. Nothing is sent and no code exists.

  1. Open the risk rules

    Go to One-time codes and press Risk rules, or open Settings and then Verification risk.

    The Verification risk settings with Mode and Always allow domainsThe Verification risk settings with Mode and Always allow domains
    Verification risk: choose the mode and the domains Notix always allows.
  2. Pick a mode

    Signals only (refuse disposable domains) refuses a code only when a signal refuses on its own, such as a disposable domain. Strict also refuses every request that scores High.

  3. Always allow your own domains

    Under Always allow domains, add one domain per line, up to 50. Notix skips the disposable domain, missing MX and role address signals for these. The speed checks still apply. Press Save.

Only a team admin can change these settings. Everyone else on the team sees them read only.

See every code you sent

One-time codes shows the week's figures at the top: codes sent, verified, the average time to enter and how many were blocked. Recent codes lists each code with its channel, recipient, risk, tries and status, such as Verified, Expired, Locked or Blocked. Filter by channel with the chips. The funnel beside it shows how many codes went from sent to verified.

The One-time codes page with weekly figures, recent codes and the sent to verified funnelThe One-time codes page with weekly figures, recent codes and the sent to verified funnel
One-time codes: this week's figures, recent codes and the funnel.

The same data is in the API: List one-time codes and Get one-time code figures. No answer ever holds a code, and phone numbers are masked to their last four digits.

Your server can follow each code with the verification.sent, verification.verified, verification.failed, verification.refused and verification.delivered webhook events.

Open in ClaudeOpen in ChatGPT