Verify phone numbers with one-time passcodes. Built-in fraud protection blocks SMS pumping attacks.
POST /v1/verify
Send a one-time passcode via SMS.
torequiredchannelrequiredtemplatecode_length// Step 1: Send the OTP to the user
const verification = await client.verify.create({
to: "+15551234567",
channel: "sms",
// Optional: custom template
template: "Your {{brand}} verification code is: {{code}}",
});
// verification.status → "pending"
// An SMS with a 6-digit code is sent to the userPOST /v1/verify/check
Verify the code entered by the user. Codes expire after 10 minutes.
// Step 2: Check the code the user entered
const result = await client.verify.check({
to: "+15551234567",
code: userEnteredCode, // e.g. "847291"
});
if (result.status === "approved") {
// ✓ User is verified — proceed with signup/login
await createUserSession(result.to);
} else {
// ✗ Invalid or expired code
return { error: "Invalid code. Please try again." };
}Fraud Guard automatically detects and blocks SMS pumping attacks — where bad actors use your API to send mass OTPs and collect carrier payouts. It runs before every verification request, at no extra cost.
// Fraud Guard is enabled by default on all verifications.
// You can monitor and configure it in the dashboard.
// Example: Check if a number was blocked
const status = await client.fraudGuard.check("+15551234567");
// status.blocked → true | false
// status.reason → "pumping_suspected" | "rate_limit" | "geo_block"Default rate limits protect you from abuse and reduce costs. Customize per your needs.
// Default rate limits per phone number:
// - 5 verification attempts per 10 minutes
// - 1 successful verification per 10 minutes (for the same number)
// Customize for your service (dashboard or API):
const service = await client.verify.services.update("VA_xxxx", {
codeLength: 6,
lookupEnabled: true,
fraudGuardEnabled: true,
rateLimits: {
maxAttempts: 3,
windowMinutes: 10,
},
});