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 dotenvSCAMVERIFY_API_KEY=sv_live_your_key_hereMiddleware 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.
Related
- Build a Phone Verification Flow for a complete Express tutorial
- Next.js Integration if you are using Next.js
- Common Issues for troubleshooting