The email rules only, with no device match. Use it before you send the signup code (OTP)to refuse throwaway addresses without paying for the email, or to show a “did you mean gmail.com?” hint. It stores nothing about the person. Requires a secret key (sk_*) and SDK 1.15.0 or later.
Signature
vevee.guard.checkEmail(email: string): Promise<GuardEmailResponse> // email max 320 charsExample
// app/api/signup/start/route.ts
import { vevee } from '@/lib/vevee'; // createClient({ apiKey: 'sk_live_...' })
export async function POST(req: Request) {
const { email } = await req.json();
const check = await vevee.guard.checkEmail(email);
if (check.suggestion) {
return Response.json({ suggestion: `Did you mean ${check.suggestion}?` });
}
if (check.recommendation === 'block') {
return Response.json({ error: 'Use a different email.' }, { status: 400 });
}
await sendSignupCode(email);
return Response.json({ ok: true });
}Response
{
email: string;
normalized: string;
domain: string;
valid: boolean;
deliverable: boolean | null; // null = unknown (DNS timeout)
disposable: boolean;
relay: boolean;
domainAgeDays: number | null; // not looked up for big consumer providers
suggestion: string | null;
sources: string[]; // diagnostic only, do not branch on it
risk: 'low' | 'medium' | 'high' | 'unknown';
recommendation: 'allow' | 'review' | 'deny_free' | 'block';
reasons: GuardReason[];
degraded: boolean;
unavailableReason: 'guard_cap_reached' | 'guard_unavailable' | 'guard_disabled' | null;
}The reasons are the email ones from guard.signup(), including email_seenwhen the same normalized email already signed up on this app. The app's mode applies: in observe mode the recommendation is always allow.
checkEmail, signup, or both
guard.signup()alone is enough: it runs the same email checks plus the device match, and it is the call that remembers signups.- Add
checkEmail()when you want to stop a throwaway address before the OTP email goes out. Each call counts once against the guard allowance, so using both costs two per signup. - Never call either on login.
Never throws
Like every guard method it resolves to an unavailable answer on any failure, with the recommendation from the guardUnavailable client option (default 'allow') and the error passed to onGuardError. Raw HTTP errors are the same as for guard.signup(): invalid_key (401), requires_secret_key (403), invalid_request (400).