The Integration Problem

Sending a code is only one step in verification. An application also needs a way to connect its sending account, authenticate API calls, prevent repeated sends, expire old codes and consume a valid code exactly once. ZaidanLab built this independent open-source project around that complete workflow. It is a functional engineering MVP, not a commissioned client deployment or a public shared sending service. The cover is a real capture of the dashboard during an isolated automated test with synthetic data; it does not show a live WhatsApp delivery.

Register the Installation, Then Connect a Number

The operator self-hosts the application and creates the single owner account using a private installation setup token. After login, the owner adds an existing WhatsApp number and activates its linked-device connection with a QR or pairing code. The gateway checks that the linked account matches the registered sending number. This registers a number with the gateway, not a new WhatsApp account. One owner can manage multiple sending numbers; public multi-tenant signup is not part of this release.

A Documented Server-to-Server API

Applications use separately revocable bearer API keys, shown once and stored as hashes. The API lists configured senders and provides POST /v1/otp/request, GET /v1/otp/{requestId} and POST /v1/otp/verify. OpenAPI 3.1 schemas come from the same route definitions used for validation. Owner-authenticated Swagger UI includes Authorize and Try it out; the dashboard also has an integration playground. These actions invoke the real API rather than a display-only mock. Application keys belong on the integrating server, not in public browser code.

Verification Is a Persistent State Machine

The server generates six-digit codes with Node's cryptographic random-number generator and stores an HMAC bound to the request ID instead of plaintext codes. SQLite transactions enforce one-time consumption and persist incorrect attempts, expiry and lockout. Defaults are a five-minute lifetime, five verification attempts and a sixty-second recipient resend cooldown. Application, sending-device, recipient and observed-IP limits complement those controls. The integrating application must bind each request ID to its own user, recipient and intended action; a successful verification response is not itself an application login token.

Retries Without Duplicate Sends

The gateway reserves the request before calling the transport. A caller-supplied Idempotency-Key maps retries to the same logical request for approximately twenty-four hours; changed request data with the same key is rejected. An accepted send means a message ID was returned, not that the recipient received it. Matching delivery/read receipts update a separate status when observed. A lost acknowledgement or interrupted send remains delivery_unknown and is never automatically resent. This makes uncertainty visible instead of hiding it behind an unconditional success message.

Self-Hosting and Source Access

The MIT-licensed public repository includes Docker Compose, an alternative resource-capped systemd template, setup instructions, API examples and operational documentation. Baileys handles the WhatsApp linked-device connection; provider considerations and responsibilities are documented in the source README. The release is designed for one process and one private persistent store, not high availability or a multi-tenant SaaS. Its hosted evaluation is private; there is no open public OTP-sending demo on this page.

What Was Verified

Thirty-three automated backend and adapter tests cover owner authentication, API-key isolation, origin checks, expiry, attempt limits, atomic verification, idempotency, uncertain acknowledgements and receipt handling. A real-browser workflow at 390px and 1280px exercises setup, number management, key creation, request/verify and Swagger authorization with Try it out. Container checks verify non-root/read-only execution and state persistence across restart; the native service also passed the backend suite. WhatsApp transport is substituted in these tests: actual number pairing and recipient delivery still require a separate operator-run check. For the design trade-offs, read the OTP API engineering guide.