ScamVerify™
Integrations

Express.js

Integrate the ScamVerify™ API with your Express.js application using middleware and route handlers.

This guide shows you how to add ScamVerify™ verification to an Express.js application using middleware for authentication and dedicated route handlers for each channel.

Environment Setup

Store your API key in a .env file and load it with dotenv.

npm install dotenv
SCAMVERIFY_API_KEY=sv_live_your_key_here

Middleware Pattern

Create a middleware that attaches a ScamVerify™ client to each request.

// middleware/scamverify.js
require('dotenv').config();

const SCAMVERIFY_API_KEY = process.env.SCAMVERIFY_API_KEY;
const BASE_URL = 'https://scamverify.ai/api/v1';

async function callScamVerify(endpoint, body) {
  const response = await fetch(`${BASE_URL}${endpoint}`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${SCAMVERIFY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  if (response.status === 401) {
    throw { status: 401, message: 'Invalid or revoked API key' };
  }
  if (response.status === 402) {
    throw { status: 402, message: 'Quota exhausted' };
  }
  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After') || '60';
    throw { status: 429, message: `Rate limited. Retry after ${retryAfter}s` };
  }
  if (!response.ok) {
    throw { status: response.status, message: `API error: ${response.status}` };
  }

  return response.json();
}

// Middleware that attaches ScamVerify methods to req
function scamverifyMiddleware(req, res, next) {
  req.scamverify = {
    lookupPhone: (phoneNumber) =>
      callScamVerify('/phone/lookup', { phone_number: phoneNumber }),

    lookupUrl: (url, forceRefresh = false) =>
      callScamVerify('/url/lookup', { url, ...(forceRefresh && { force_refresh: true }) }),

    analyzeText: (text, senderNumber = null) =>
      callScamVerify('/text/analyze', {
        text,
        ...(senderNumber && { sender_number: senderNumber }),
      }),

    analyzeEmail: (emailBody, rawHeaders = null) =>
      callScamVerify('/email/analyze', {
        email_body: emailBody,
        ...(rawHeaders && { raw_headers: rawHeaders }),
      }),

    batchPhone: (phoneNumbers) =>
      callScamVerify('/batch/phone', {
        items: phoneNumbers.map((n) => ({ phone_number: n })),
      }),

    batchUrl: (urls) =>
      callScamVerify('/batch/url', {
        items: urls.map((u) => ({ url: u })),
      }),
  };

  next();
}

module.exports = { scamverifyMiddleware, callScamVerify };

Route Handlers

Apply the middleware globally or to specific routes, then use the attached client.

// server.js
require('dotenv').config();
const express = require('express');
const { scamverifyMiddleware } = require('./middleware/scamverify');

const app = express();
app.use(express.json());

// Apply to all verification routes
app.use('/api/verify', scamverifyMiddleware);

// Phone verification
app.post('/api/verify/phone', async (req, res) => {
  const { phone_number } = req.body;

  if (!phone_number) {
    return res.status(400).json({ error: 'phone_number is required' });
  }

  try {
    const result = await req.scamverify.lookupPhone(phone_number);
    return res.json(result);
  } catch (error) {
    return res.status(error.status || 500).json({ error: error.message });
  }
});

// URL verification
app.post('/api/verify/url', async (req, res) => {
  const { url } = req.body;

  if (!url) {
    return res.status(400).json({ error: 'url is required' });
  }

  try {
    const result = await req.scamverify.lookupUrl(url);
    return res.json(result);
  } catch (error) {
    return res.status(error.status || 500).json({ error: error.message });
  }
});

// Text analysis
app.post('/api/verify/text', async (req, res) => {
  const { text, sender_number } = req.body;

  if (!text) {
    return res.status(400).json({ error: 'text is required' });
  }

  try {
    const result = await req.scamverify.analyzeText(text, sender_number);
    return res.json(result);
  } catch (error) {
    return res.status(error.status || 500).json({ error: error.message });
  }
});

// Email analysis
app.post('/api/verify/email', async (req, res) => {
  const { email_body, raw_headers } = req.body;

  if (!email_body) {
    return res.status(400).json({ error: 'email_body is required' });
  }

  try {
    const result = await req.scamverify.analyzeEmail(email_body, raw_headers);
    return res.json(result);
  } catch (error) {
    return res.status(error.status || 500).json({ error: error.message });
  }
});

// Batch phone lookup
app.post('/api/verify/batch/phone', async (req, res) => {
  const { phone_numbers } = req.body;

  if (!phone_numbers || !Array.isArray(phone_numbers)) {
    return res.status(400).json({ error: 'phone_numbers array is required' });
  }

  if (phone_numbers.length > 50) {
    return res.status(400).json({ error: 'Maximum 50 numbers per batch' });
  }

  try {
    const result = await req.scamverify.batchPhone(phone_numbers);
    return res.json(result);
  } catch (error) {
    return res.status(error.status || 500).json({ error: error.message });
  }
});

// Error handling middleware
app.use((err, req, res, next) => {
  console.error('Unhandled error:', err);
  res.status(500).json({ error: 'Internal server error' });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Error Handling

Create a centralized error handler for ScamVerify™ API errors.

// middleware/error-handler.js
function scamverifyErrorHandler(err, req, res, next) {
  if (err.status === 401) {
    console.error('ScamVerify: API key invalid or revoked');
    return res.status(500).json({ error: 'Verification service misconfigured' });
  }

  if (err.status === 402) {
    return res.status(503).json({
      error: 'Verification temporarily unavailable',
      reason: 'quota_exhausted',
    });
  }

  if (err.status === 429) {
    return res.status(429).json({
      error: 'Too many requests',
      message: err.message,
    });
  }

  next(err);
}

module.exports = { scamverifyErrorHandler };

Testing

Use sv_test_ keys during development and testing. Test keys return realistic mock data without consuming quota.

// test/verify-phone.test.js
const request = require('supertest');
const app = require('../server');

describe('POST /api/verify/phone', () => {
  it('returns a risk assessment', async () => {
    const response = await request(app)
      .post('/api/verify/phone')
      .send({ phone_number: '+12025551234' })
      .expect(200);

    expect(response.body).toHaveProperty('risk_score');
    expect(response.body).toHaveProperty('verdict');
    expect(response.body).toHaveProperty('explanation');
  });

  it('returns 400 for missing phone number', async () => {
    await request(app)
      .post('/api/verify/phone')
      .send({})
      .expect(400);
  });
});

TypeScript users: The same patterns work with express and @types/express. Add type annotations to the middleware and use interfaces for the ScamVerify™ response shapes.

On this page