1. Run the application tests offline
2. Prepare a permitted Sandbox request
Complete the Quickstart. You need Sandbox access to create, verify and retrieve OTP challenges for your business, an authorized sender, a permitted test recipient and an approved OTP template key. If OTP is unavailable for your business, contact Support before continuing. See OTP integration for the workflow. In the application directory:request.json, replacing the sender, destination and template key:
template_key identifies an approved OTP template. It is distinct from an SMS
template_id. If business policy permits inline OTP content, this alternative
request includes the required {{code}} placeholder and omits template_key:
3. Create the challenge and save its ID
login-1001 is this attempt’s stable application session ID; user-42 represents
the application user. The terminal operator supplies both in this exercise. A
web integration must obtain user/session identity from trusted server context;
accepting a caller-supplied user ID is not authentication.
Before POST, the application commits an idempotency key and request bytes to
SQLite. It requires HTTP 202, then saves the returned challenge ID, status,
code_length and expires_at. The create response never includes the code.
Acceptance does not mean the SMS was delivered.
If the response is lost, repeat the exact command with the same request and
database. It reuses the saved key/body instead of creating a new attempt. Once
an ID is saved, it skips another create POST. Changing the payload or subject
under the same local session is rejected. Follow
idempotency recovery if acceptance remains
uncertain beyond the seven-day replay window.
4. Verify the code against the saved challenge
200, the saved challenge ID, the original purpose and
status: verified. The application persists verification_state: verified
and verified_at. It does not issue a login token or claim SMS delivery. A
repeat local verify command is blocked instead of making another POST.
5. Handle rejected and uncertain attempts
A wrong code returns HTTP422 with otp_verification_failed. The application
records that error and permits a deliberate new recipient submission. The
platform still enforces its attempt limit; there is no automatic code retry.
Expiry returns HTTP 422 with otp_challenge_expired. Lockout returns HTTP
429 with otp_challenge_locked. Invalidation and an already consumed code
return HTTP 409 with their distinct codes. These block verification locally;
none are treated as a new successful check. For other 429 responses, inspect
the error code and respect Retry-After. See
Error handling.
If verification times out or the process exits during the request, the database
retains verification_state: uncertain. Inspect it and retrieve current state:
200 from
Retrieve OTP challenge status.
A GET reporting verified is an observation, not evidence that a fresh code
submission succeeded in this application. The example keeps local proof
uncertain and issues no token. Apply your product’s reviewed recovery policy;
do not blindly retry verification or edit local state to manufacture success.
After a definitively expired or blocked flow, a user can explicitly begin a new
attempt under your product policy with a new local session ID. Do not do this
just to bypass an uncertain response, cooldown or attempt limit. Follow
Resend and invalidate challenges for those
separate actions; the application performs neither automatically.