WhatsApp-based authentication for your mobile apps
TapAuth provides a simple WhatsApp-based authentication system for mobile applications. Your app submits the end user's WhatsApp number, the user sends a message to our bot, the bot verifies the number matches, and your app polls until the session is verified.
Base URL: https://tapauth.my.id/api
Authentication: All API requests require an API key in the X-API-KEY header. Call these endpoints from your backend only — never embed the API key in a mobile app. Your mobile app should poll your backend, and your backend proxies to TapAuth.
Use our official SDKs to integrate TapAuth quickly:
Simple PHP client with cURL support
→ Download TapAuthClient.php
Modern JavaScript client with fetch API
→ Download tapauth.js
Documentation: PHP README | Node.js README
POST /v1/auth/request with the user's wa_number to initiate authenticationwa_numberverified; the bot replies with a success messagePOST /v1/auth/verify until the session is verified/v1/auth/request
Initiate an authentication session and get WhatsApp URL for user.
X-API-KEY: tap_your_api_key_here
{
"wa_number": "6281234567890"
}
wa_number (the end user's WhatsApp number) is required. The bot verifies that the sender matches this number.
{
"success": true,
"identifier": "TAP-XXXXXXXXXXXX",
"whatsapp_url": "whatsapp://send?phone=628123456789&text=...",
"expires_in": 300
}
401 - Invalid or missing API key402 - Insufficient balance429 - Too many pending sessions (max 10)503 - No bot device available/v1/auth/verify
Check the session status. Once the session is verified, this returns the user info and deducts Rp50 from your balance. Poll this endpoint until it succeeds.
X-API-KEY: tap_your_api_key_here
{
"identifier": "TAP-XXXXXXXXXXXX"
}
{
"status": "success",
"wa_number": "6281234567890",
"push_name": "John Doe"
}
While the user has not completed verification, keep polling. The reason field is waiting, or rejected if the bot found the number did not match.
{
"error": "Session not ready for verification",
"reason": "waiting",
"message": "Menunggu verifikasi WhatsApp"
}
400 - Session not ready (reason: waiting or rejected)401 - Invalid or missing API key404 - Session not foundAfter requesting authentication, your backend should poll the verify endpoint to check if the user has completed verification via WhatsApp. Your mobile app polls your backend at an interval (e.g. every 3s), and your backend forwards the check to TapAuth using the API key.
Flow (mobile → your backend → TapAuth):
wa_number to your backend; your backend calls /v1/auth/request and returns the identifier + WhatsApp URL/v1/auth/verify (a 400 with reason: waiting means keep polling) until it succeedsRp50
per successful authentication
New users get Rp5,000 welcome bonus (100 free authentications)
These examples run on your backend (the API key stays server-side). Your mobile app calls your backend, and your backend runs the request/verify polling below.
// Request authentication (send the user's WhatsApp number)
const response = await fetch('https://tapauth.my.id/api/v1/auth/request', {
method: 'POST',
headers: {
'X-API-KEY': 'tap_your_api_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ wa_number: '6281234567890' })
});
const data = await response.json();
// Open WhatsApp
window.location.href = data.whatsapp_url;
// Poll verify until the session is verified
async function poll(identifier) {
while (true) {
const res = await fetch('https://tapauth.my.id/api/v1/auth/verify', {
method: 'POST',
headers: {
'X-API-KEY': 'tap_your_api_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ identifier })
});
const result = await res.json();
if (res.ok && result.status === 'success') {
console.log(result.wa_number, result.push_name);
return result;
}
if (result.reason === 'rejected') {
throw new Error(result.message);
}
// reason === 'waiting' → try again shortly
await new Promise(r => setTimeout(r, 3000));
}
}
await poll(data.identifier);
// Request authentication (send the user's WhatsApp number)
$ch = curl_init('https://tapauth.my.id/api/v1/auth/request');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-KEY: tap_your_api_key_here',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'wa_number' => '6281234567890'
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch));
// Poll verify until the session is verified
while (true) {
$ch = curl_init('https://tapauth.my.id/api/v1/auth/verify');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-KEY: tap_your_api_key_here',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'identifier' => $response->identifier
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$userData = json_decode($body);
if ($code === 200 && $userData->status === 'success') {
echo $userData->wa_number;
break;
}
if (isset($userData->reason) && $userData->reason === 'rejected') {
throw new Exception($userData->message);
}
sleep(3); // reason === 'waiting'
}
import requests
import time
# Request authentication (send the user's WhatsApp number)
response = requests.post(
'https://tapauth.my.id/api/v1/auth/request',
headers={'X-API-KEY': 'tap_your_api_key_here'},
json={'wa_number': '6281234567890'}
)
data = response.json()
# Poll verify until the session is verified
while True:
res = requests.post(
'https://tapauth.my.id/api/v1/auth/verify',
headers={'X-API-KEY': 'tap_your_api_key_here'},
json={'identifier': data['identifier']}
)
result = res.json()
if res.status_code == 200 and result.get('status') == 'success':
print(result['wa_number'], result['push_name'])
break
if result.get('reason') == 'rejected':
raise Exception(result['message'])
time.sleep(3) # reason == 'waiting'
For questions or support, please contact us through your dashboard or email [email protected]
© 2026 TapAuth. All rights reserved.