Drop a single REST call into your signup, login or checkout flow and deliver 6-digit codes over email and SMS. Hashed at rest, expired on schedule, rate limited by IP, key and account.
curl -X POST https://www.otp.dearprime.in/api/v1/send-otp \
-H "Content-Type: application/json" \
-d '{
"api_key": "otp_live_xxxxxxxxxxxx",
"email": "user@example.com",
"mobile": "9876543210",
"purpose": "signup"
}'
{
"success": true,
"message": "OTP sent successfully",
"request_id": "REQ_3f2a91c0b7d5e468",
"expires_in": 300
}
Codes are stored as salted SHA-256 digests. Never logged, never shown.
SMTP and SMS providers are called synchronously - no queue workers needed.
Every request appears in your API log with status, latency and request ID.
Per IP, per key, per account and per destination limits enforced in the database.
Two endpoints, one dashboard, zero infrastructure to babysit.
Send to an email address, a mobile number, or both in the same request.
Code length, lifetime, retry count and resend cooldown are all tunable.
A 60 second per-destination cooldown stops accidental double sends.
Codes lock after the configured number of failed verification attempts.
Destinations are masked in the UI: 98******10 and us***@example.com.
Fire real requests from your dashboard and inspect the raw JSON response.
Register, open API Keys and generate a cryptographically random secret. It is shown once.
POST the destination and a purpose to /api/v1/send-otp and store the returned request_id.
POST the request_id plus the code the user typed to /api/v1/verify-otp. Done.
$payload = [
'api_key' => getenv('OTP_API_KEY'),
'request_id' => $_POST['request_id'],
'otp' => $_POST['otp'],
];
$ch = curl_init('https://www.otp.dearprime.in/api/v1/verify-otp');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
]);
$res = json_decode(curl_exec($ch), true);
if (!empty($res['verified'])) {
// mark the user as verified
}
Examples in cURL, PHP and JavaScript for every endpoint.
const res = await fetch('/api/v1/send-otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: API_KEY,
email: 'user@example.com',
purpose: 'login'
})
});
const data = await res.json();
console.log(data.request_id);
Every failure returns a stable machine-readable code with the right HTTP status - never a stack trace.
| Status | Code |
|---|---|
| 401 | INVALID_API_KEY |
| 422 | VALIDATION_ERROR |
| 429 | RATE_LIMIT_EXCEEDED |
| 400 | INVALID_OTP |
API keys and OTP codes are stored as peppered SHA-256 hashes - the plaintext leaves the server once.
Every query uses PDO prepared statements with emulation disabled.
Session-bound CSRF tokens on all forms and strict output escaping everywhere.
HttpOnly, SameSite cookies, id rotation on login and periodic regeneration.
IP, API key, account, destination and per-code attempt counters.
Admin actions, login attempts and API calls are all recorded.
Every plan includes both channels, full logs and the test console.
Yes. Provide both fields and the same code is delivered on both channels under one request_id.
Only a peppered SHA-256 hash is stored. The plaintext code exists in memory for the duration of the send request.
The attempt counter increments. After the configured maximum (5 by default) the code is locked and a new one must be requested.
No. Delivery is synchronous and rate limiting is stored in MySQL, so the platform runs on ordinary shared hosting.
Yes. The SMS layer is an interface - configure any provider REST endpoint in the admin panel or add a class for it.
Create an account, pick a plan, generate a key and send your first code today.