# WhatsOS OTP API integration context for coding assistants Build a server-side phone verification integration using the existing WhatsOS API. API base: https://whatsos.com/api/v1/otp OpenAPI: https://whatsos.com/otp/openapi.json Guide: https://whatsos.com/otp/guide.html Integration downloads: https://whatsos.com/otp/integrations.html Do not invent endpoints, scopes or pricing. Read OpenAPI before writing code. Keep WHATSOS_OTP_KEY in server-side environment/configuration only. Never include it in React/Next.js client bundles, NEXT_PUBLIC_* variables, mobile apps, prompts or logs. Use separate wotp_test_ and wotp_live_ project keys. Test projects simulate delivery with code 123456. Test results must not authenticate users or approve production actions. API contract: - POST /verifications {to, purpose, locale?, reference?}: requests a code (202). - POST /verifications/{id}/check {code}: check user input (200). - POST /verifications/{id}/resend {}: replaces a challenge after cooldown (202). - POST /verifications/{id}/cancel {}: cancel an active challenge (200). - GET /verifications/{id}: read masked state (200). All requests: Authorization: Bearer SERVER_API_KEY; JSON over HTTPS. Every POST: Idempotency-Key with 8-128 characters [A-Za-z0-9_.:-]. Use otp:send for send/resend; otp:verify for check; otp:read for GET; otp:cancel for cancel. Phone: E.164 (+countrycode and number). Code: exactly six digits, stored as a string. Purpose must be enabled in the project (defaults: login, signup, phone_verification). Locale must match the project's configured authentication template language. Implement an application-owned server session for each verification attempt. Store the verification_id, intended phone, purpose and environment against that session. Never accept an arbitrary verification_id from a browser as authorization to complete someone else's action. Do not log API keys, OTP codes or full phone numbers. Mask user-facing phone numbers. Generate a new idempotency key for each logical send/check/resend/cancel. Save it before the request. On a timeout or ambiguous network failure, retry the SAME payload and SAME key. Do not retry a different code or payload under the old key. A definite rate-limit rejection requires waiting before starting a new operation. Honor Retry-After and resend_after. A resend returns a NEW verification_id; replace the old server-side binding. Approve the bound action only when check returns verified === true, in the intended live project and session. Sending, message delivery and HTTP 200 alone do not mean verified. Consume your application's verification proof atomically once; upstream idempotency replay may return an earlier true result. Expire local attempts and clear them on logout/cancellation. Protect public application endpoints with CSRF/session binding and per-IP/per-phone abuse limits. Add a CAPTCHA or equivalent abuse control appropriate to the application. Handle incorrect code, expired, locked, cancelled, superseded, invalid key, quota/setup, 429 and 503 states. Never fail open during outages. For signed webhooks, validate the original bytes, timestamp and HMAC according to the guide; reject stale signatures and deduplicate event IDs. Do not use unverified webhooks for login. Test with mocks or test projects only. Do not send real OTPs or create paid traffic by default. WordPress: download the official WhatsOS plugin from the integration page. Use [whatsos_otp] in a Shortcode block/widget. For a protected server action call whatsos_otp_consume($expected_phone, 'phone_verification'); reject WP_Error results. This plugin provides phone verification, not automatic WordPress/WooCommerce login. The browser's whatsos:verified event is UI feedback, never proof for a protected action.