Better Auth is a TypeScript auth library that runs inside your own server, so the check runs in your code, with your secret key, before the user exists. Better Auth lets you run code before endpoints execute and before database records are created. Its “Hooks” and “Database hooks” docs show the current signatures. Call the helper below from whichever fits your setup.
1. The helper
// lib/work-email.ts
export type Verdict = {
category?: string;
recommendation: 'allow' | 'review' | 'block';
did_you_mean?: string | null;
workspace?: {
google_workspace?: { detected: boolean };
microsoft_365?: { detected: boolean; tenant_id: string | null };
};
failOpen?: boolean;
};
export async function checkWorkEmail(email: string): Promise<Verdict> {
try {
const res = await fetch('https://api.isbusinessemail.com/v1/check', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.IBE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
signal: AbortSignal.timeout(2500),
});
if (!res.ok) return { recommendation: 'allow', failOpen: true };
return (await res.json()) as Verdict;
} catch {
return { recommendation: 'allow', failOpen: true };
}
}
2. Where to call it
| Hook point | Covers | On block |
|---|---|---|
| Before the email sign-up endpoint runs | Email/password sign-ups | Throw an error with a friendly message; the client receives it |
| Before a user record is created | Every new user, including social and magic-link sign-ins | Abort the creation, or allow it and store a “needs work email” flag |
In both cases the logic is the same:
const verdict = await checkWorkEmail(email);
if (verdict.recommendation === 'block') {
// reject with a message such as:
// "Please use your work email." + (verdict.did_you_mean ? ` Did you mean ${verdict.did_you_mean}?` : '')
}
// otherwise continue, and persist verdict.category (and workspace detection) on the user
If you store the verdict on the user, add columns or additional user fields for email_category, google_workspace and microsoft_365, so your app can route onboarding without calling the API again.
Tips
- Social sign-ins skip the email endpoint, so the “before user created” hook point is the one that catches everything.
- Fail open on timeouts and mark the user for a background re-check.
- Test with
personal@test.isbusinessemail.comandworkspace@test.isbusinessemail.com(test addresses).
Official docs: Better Auth documentation. See also: Signup form guide.