Managed mode
The default. LazyApp generates the code, sends it, and verifies it later. You never see or store it.1
Send
2
Verify
422 with "code": "otp_invalid". A verified challenge cannot be verified twice.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: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 acode, 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.
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
Ansk_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 approvedAUTHENTICATION 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 receiveotp.requested, otp.verified and otp.failed. Codes are redacted from all three.