Skip to main content
WhatsApp OTP delivery is cheaper and more reliable than SMS in many markets. LazyApp handles generation, hashing, delivery, verification and abuse controls.

Managed mode

The default. LazyApp generates the code, sends it, and verifies it later. You never see or store it.
1

Send

client_ip is your end user’s address, not your server’s. It is optional; see Limits.
Keep the id.
2

Verify

A wrong code returns 422 with "code": "otp_invalid". A verified challenge cannot be verified twice.
You can verify by to instead of id if carrying the id through your flow is awkward.

Delivery-only mode

When your existing auth system already generates codes, LazyApp just delivers:
You verify it yourself. LazyApp does not retain the code.

What LazyApp enforces

Never stored in plaintext

Codes are hashed with a keyed mechanism at creation. There is nothing to leak.

Redacted everywhere

Codes are stripped from request logs and from webhook payloads, so an OTP cannot leak to your own logging pipeline.

Attempt limits

Wrong guesses are capped per challenge, and a verified challenge cannot be replayed.

Abuse controls

Per-recipient daily caps, per-team and per-IP rate limits, and a resend delay to stop someone using your account to spam a number.

Limits

Refusals carry a code, so your sign-in page can show the right message without matching English text. When waiting is the answer, the response is 429 with a Retry-After header and retry_after in the body.
The per-IP rule only applies when you pass client_ip. A website sends every sign-in from its own server, so applying the rule to the server’s address would stop it after a handful of users. Pass your end user’s address and the rule protects you from one person cycling through numbers. Sending and verifying have separate per-key rate limits (see Rate limits).

Test mode

An sk_test_ key sends through your sandbox number, so test codes reach real phones on your test recipient list and verify exactly as they do live.

Templates

OTPs need an approved AUTHENTICATION template. Pass template_name to choose one, or let LazyApp use the workspace default. Authentication templates support one-tap autofill and copy-code buttons, which materially improve completion rates. Without a template, a code can only go as plain text while the number has messaged you in the last 24 hours, because WhatsApp refuses free-form messages outside that window. Anywhere else the request is refused with otp_template_required rather than sent to fail. The template goes out in the language you pass. Without one, LazyApp uses the template’s language when it has only one, so an en or hi template works without configuration.

Webhooks

You receive otp.requested, otp.verified and otp.failed. Codes are redacted from all three.