Send and verify OTP codes over WhatsApp. Use this page for quick integration and error handling.
/auth/start with the user phone number./auth/verify with the returned session_id and the OTP code entered by the user.curl -X POST https://api.loginwa.com/api/v1/auth/start \
-H "Authorization: Bearer <SECRET_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"phone":"6281234567890","meta":{"user_id":"123"}}'
curl -X POST https://api.loginwa.com/api/v1/auth/verify \
-H "Authorization: Bearer <SECRET_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"session_id":"<SESSION_ID>","otp_code":"123456"}'
Authorization: Bearer <SECRET_API_KEY> (or X-Api-Key).application/json.curl -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
https://api.loginwa.com/api/v1/auth/start
Use different keys per project to isolate traffic, usage, and logs.
{"phone": "628...", "meta": {"user_id": "optional"}}session_id, expires_in, and sent_via_engine flag.401 unauthorized, 422 invalid_phone, 429 quota_exceeded.{
"session_id": "3bbaaf0b-3c11-44a2-8a7e-4edc426c5fcd",
"expires_in": 300,
"sent_via_engine": true
}
{"session_id": "...", "otp_code": "123456"}status, phone, and verified_at on success.401 unauthorized, 422 invalid_code | expired | blocked.{
"status": "verified",
"phone": "6281234567890",
"verified_at": "2025-11-28T12:00:00Z"
}
quota_exceeded.Use dashboard logs to monitor success rate, failures, and per-app usage.
401 unauthorized — missing/invalid API key.422 invalid_phone — phone format cannot be parsed.422 invalid_code / expired / max_attempts — verification failed.429 quota_exceeded — monthly quota finished for this key.Handle 4xx gracefully and let users retry or request a new OTP after cooldown.
$client = new \GuzzleHttp\Client();
$res = $client->post('https://api.loginwa.com/api/v1/auth/start', [
'headers' => [ 'Authorization' => 'Bearer '.getenv('API_KEY') ],
'json' => [ 'phone' => '6281234567890' ]
]);
$body = json_decode((string) $res->getBody(), true);
const res = await fetch('https://api.loginwa.com/api/v1/auth/start', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ phone: '6281234567890' })
});
const data = await res.json();
curl -X POST https://api.loginwa.com/api/v1/auth/start \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"6281234567890"}'
Need help with integration, higher limits, or production cutover?