> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vouch.expert/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js SDK

> Server-side email validation for Node.js applications

## Overview

The Vouch Node.js SDK enables server-side email validation with higher rate limits and no domain restrictions. Perfect for backend APIs, serverless functions, and batch processing.

<Note>
  **Package:** `@vouch-in/node`
  **Node Version:** 18+ required
  **TypeScript:** Full type definitions included
</Note>

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @vouch-in/node
  ```

  ```bash yarn theme={null}
  yarn add @vouch-in/node
  ```

  ```bash pnpm theme={null}
  pnpm add @vouch-in/node
  ```
</CodeGroup>

## Quick Start

```javascript theme={null}
import { Vouch } from '@vouch-in/node';

// Initialize with server API key
const vouch = new Vouch(
  process.env.VOUCH_PROJECT_ID,
  process.env.VOUCH_SERVER_KEY
);

// Validate an email
const result = await vouch.validate('user@example.com');

// Check the recommendation
if (result.recommendation === 'allow') {
  console.log('Email is valid!');
} else {
  // Option 1: Use the message field for a user-friendly error
  console.log(result.message); // e.g. "Please use a permanent email address, not a temporary one."

  // Option 2: Check specific validations for custom messages
  if (!result.checks.syntax?.pass) {
    throw new Error('Invalid email format');
  }
  if (!result.checks.disposable?.pass) {
    throw new Error('Disposable email not allowed');
  }
}
```

## Validate with Request Context

Pass IP and User-Agent for better fraud detection:

```javascript theme={null}
const result = await vouch.validate('user@example.com', {
  ip: req.ip,
  userAgent: req.headers['user-agent'],
  fingerprintHash: req.body.fingerprintHash, // From client SDK
});
```

## Express.js Integration

```javascript theme={null}
import express from 'express';
import { Vouch } from '@vouch-in/node';

const app = express();
const vouch = new Vouch(PROJECT_ID, SERVER_KEY);

app.post('/api/signup', async (req, res) => {
  const { email, fingerprintHash } = req.body;

  try {
    const result = await vouch.validate(email, {
      ip: req.ip,
      userAgent: req.get('user-agent'),
      fingerprintHash, // Optional: from client SDK
    });

    const { checks, metadata, recommendation } = result;

    // Check critical validations
    if (!checks.syntax?.pass) {
      return res.status(400).json({
        error: 'Invalid email format'
      });
    }

    if (!checks.disposable?.pass) {
      return res.status(400).json({
        error: 'Disposable emails not allowed'
      });
    }

    // Check for suspicious activity
    if (recommendation === 'block') {
      return res.status(400).json({
        error: 'This email cannot be used'
      });
    }

    if (metadata.previousSignups > 10) {
      return res.status(400).json({
        error: 'Too many accounts from this device'
      });
    }

    // Create user
    const user = await createUser(email);

    res.json({ success: true, user });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});
```

## Serverless Functions

### AWS Lambda

```javascript theme={null}
import { Vouch } from '@vouch-in/node';

const vouch = new Vouch(
  process.env.VOUCH_PROJECT_ID,
  process.env.VOUCH_SERVER_KEY
);

export const handler = async (event) => {
  const { email } = JSON.parse(event.body);

  const result = await vouch.validate(email, {
    ip: event.requestContext?.identity?.sourceIp,
    userAgent: event.headers?.['user-agent'],
  });

  if (result.recommendation !== 'allow') {
    return {
      statusCode: 400,
      body: JSON.stringify({
        error: 'Email validation failed',
        recommendation: result.recommendation
      })
    };
  }

  return {
    statusCode: 200,
    body: JSON.stringify({ success: true })
  };
};
```

### Vercel

```javascript theme={null}
import { Vouch } from '@vouch-in/node';

const vouch = new Vouch(
  process.env.VOUCH_PROJECT_ID,
  process.env.VOUCH_SERVER_KEY
);

export default async function handler(req, res) {
  const { email } = req.body;

  const result = await vouch.validate(email, {
    ip: req.headers['x-forwarded-for'] || req.socket.remoteAddress,
    userAgent: req.headers['user-agent'],
  });

  if (result.recommendation !== 'allow') {
    return res.status(400).json({
      error: 'Email validation failed'
    });
  }

  res.status(200).json({ success: true });
}
```

### Cloudflare Workers

```javascript theme={null}
import { Vouch } from '@vouch-in/node';

export default {
  async fetch(request, env) {
    const vouch = new Vouch(env.VOUCH_PROJECT_ID, env.VOUCH_SERVER_KEY);

    const { email } = await request.json();

    const result = await vouch.validate(email, {
      ip: request.headers.get('cf-connecting-ip'),
      userAgent: request.headers.get('user-agent'),
    });

    if (result.recommendation !== 'allow') {
      return new Response(JSON.stringify({ error: 'Validation failed' }), {
        status: 400,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    return new Response(JSON.stringify({ success: true }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
};
```

## API Reference

### Constructor

```typescript theme={null}
new Vouch(projectId: string, apiKey: string, options?: VouchOptions)
```

**Parameters:**

<ParamField path="projectId" type="string" required>
  Your Vouch project ID
</ParamField>

<ParamField path="apiKey" type="string" required>
  Your server API key
</ParamField>

<ParamField path="options" type="VouchOptions">
  Optional configuration:

  * `endpoint` - API endpoint URL (default: "[https://api.vouch.expert](https://api.vouch.expert)")
  * `apiVersion` - API version number or "latest" (default: "latest")
</ParamField>

### validate()

```typescript theme={null}
vouch.validate(email: string, options?: ValidationRequestOptions): Promise<ValidationResponse>
```

**Parameters:**

<ParamField path="email" type="string" required>
  Email address to validate
</ParamField>

<ParamField path="options" type="object">
  Optional request options:

  * `ip` - Client IP address for IP reputation checks
  * `userAgent` - Client user agent
  * `fingerprintHash` - Device fingerprint hash from client SDK
</ParamField>

**Returns:** `Promise<ValidationResponse>`

```typescript theme={null}
interface ValidationResponse {
  checks: Record<string, CheckResult>;
  message: string | null;
  metadata: {
    fingerprintHash: string | null;
    previousSignups: number;
    totalLatency: number;
  };
  recommendation: 'allow' | 'block' | 'flag';
  signals: string[];
}

interface CheckResult {
  pass: boolean;
  error?: string;
  latency: number;
  metadata?: Record<string, unknown>;
}
```

<Note>
  The `message` field contains a human-friendly error message when the recommendation is `flag` or `block` (e.g. "Please use a permanent email address, not a temporary one."). It is `null` when the recommendation is `allow`.
</Note>

## Server vs Client Keys

<Warning>
  Always use **server keys** on the backend. Never expose server keys in client-side code!
</Warning>

| Feature             | Client Key   | Server Key   |
| ------------------- | ------------ | ------------ |
| Domain Restrictions | Yes          | No           |
| Rate Limits         | 1,000/hour   | 5,000/hour   |
| Override IP/UA      | No           | Yes          |
| Use Case            | Browser apps | Backend APIs |

## TypeScript Support

```typescript theme={null}
import { Vouch, ValidationResponse, CheckResult } from '@vouch-in/node';

const vouch = new Vouch(projectId, apiKey);

const result: ValidationResponse = await vouch.validate('user@example.com', {
  ip: '192.168.1.1',
  userAgent: 'Mozilla/5.0...'
});

// Type-safe access
const { checks, metadata, recommendation } = result;

if (recommendation === 'block') {
  throw new Error('Email blocked');
}

const syntaxCheck: CheckResult | undefined = checks.syntax;
if (syntaxCheck && !syntaxCheck.pass) {
  throw new Error('Invalid email format');
}
```

## Error Handling

```javascript theme={null}
try {
  const result = await vouch.validate(email, { ip, userAgent });

  if (result.recommendation === 'block') {
    throw new Error('Email blocked by policy');
  }

  // Process valid email
} catch (error) {
  if (error.message === 'Invalid email format') {
    // Client-side validation failed before API call
    return res.status(400).json({ error: 'Invalid email format' });
  }

  // Network or API error
  console.error('Validation error:', error);
  return res.status(500).json({ error: 'Validation service unavailable' });
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Next.js SDK" icon="N" href="/sdks/nextjs">
    Next.js integration
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/validate">
    Complete API docs
  </Card>
</CardGroup>
