Skip to content

JavaScript / TypeScript

Node.js 18+ includes fetch and AbortSignal.timeout natively — no additional dependencies required.

For older Node.js versions:

Terminal window
npm install node-fetch
async function verifySubmission(formData) {
const response = await fetch('https://api.formsentry.ai/v1/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: process.env.FORMSENTRY_API_KEY,
formId: process.env.FORMSENTRY_FORM_ID,
payload: formData
}),
signal: AbortSignal.timeout(5000)
});
if (!response.ok) {
throw new Error(`FormSentry error: ${response.status}`);
}
return response.json();
}
// Usage
verifySubmission({
name: 'John Doe',
email: 'john@example.com',
message: 'I would like to learn more about your services.'
})
.then(result => {
if (result.status === 'spam') {
console.log('Spam detected:', result.reasoning);
} else {
console.log('Legitimate submission');
}
})
.catch(console.error);
import express from 'express';
const app = express();
app.use(express.json());
app.post('/contact', async (req, res) => {
const { name, email, message } = req.body;
if (!name || !email || !message) {
return res.status(400).json({ error: 'Missing required fields' });
}
let result;
try {
const verification = await fetch('https://api.formsentry.ai/v1/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: process.env.FORMSENTRY_API_KEY,
formId: process.env.FORMSENTRY_FORM_ID,
payload: { name, email, message }
}),
signal: AbortSignal.timeout(5000)
});
if (!verification.ok) throw new Error(`HTTP ${verification.status}`);
result = await verification.json();
} catch (error) {
// Fail open — if FormSentry is unreachable, allow the submission
console.error('FormSentry error:', error.message);
result = { status: 'legitimate', confidence: 0.0 };
}
if (result.status === 'spam') {
// Silently accept to avoid tipping off spammers
return res.json({ success: true });
}
// TODO: Process the legitimate submission
// e.g., save to database, send email notification
res.json({ success: true });
});
app.listen(3000);
import Fastify from 'fastify';
const app = Fastify();
app.post('/contact', async (request, reply) => {
const { name, email, message } = request.body ?? {};
if (!name || !email || !message) {
return reply.status(400).send({ error: 'Missing required fields' });
}
let result;
try {
const verification = await fetch('https://api.formsentry.ai/v1/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: process.env.FORMSENTRY_API_KEY,
formId: process.env.FORMSENTRY_FORM_ID,
payload: { name, email, message }
}),
signal: AbortSignal.timeout(5000)
});
if (!verification.ok) throw new Error(`HTTP ${verification.status}`);
result = await verification.json();
} catch (error) {
// Fail open — if FormSentry is unreachable, allow the submission
console.error('FormSentry error:', error.message);
result = { status: 'legitimate', confidence: 0.0 };
}
if (result.status === 'spam') {
return reply.send({ success: true });
}
// TODO: Process legitimate submission
reply.send({ success: true });
});
app.listen({ port: 3000 });
app/api/contact/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
let formData;
try {
formData = await request.json();
} catch {
return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
}
if (!formData?.name || !formData?.email || !formData?.message) {
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
}
let result;
try {
const verification = await fetch('https://api.formsentry.ai/v1/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: process.env.FORMSENTRY_API_KEY,
formId: process.env.FORMSENTRY_FORM_ID,
payload: formData
}),
signal: AbortSignal.timeout(5000)
});
if (!verification.ok) throw new Error(`HTTP ${verification.status}`);
result = await verification.json();
} catch (error) {
// Fail open — if FormSentry is unreachable, allow the submission
console.error('FormSentry error:', error);
result = { status: 'legitimate', confidence: 0.0 };
}
if (result.status === 'spam') {
return NextResponse.json({ success: true });
}
// TODO: Process legitimate submission
return NextResponse.json({ success: true });
}
interface FormSentryRequest {
apiKey: string;
formId: string;
payload: Record<string, unknown>;
}
interface FormSentryResponse {
status: 'legitimate' | 'spam';
confidence: number;
reasoning: string;
submissionId: string;
processingTime: number;
formId?: string;
}
async function verify(payload: Record<string, unknown>): Promise<FormSentryResponse> {
const response = await fetch('https://api.formsentry.ai/v1/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: process.env.FORMSENTRY_API_KEY,
formId: process.env.FORMSENTRY_FORM_ID,
payload
} satisfies FormSentryRequest),
signal: AbortSignal.timeout(5000)
});
if (!response.ok) {
throw new Error(`FormSentry error: ${response.status}`);
}
return response.json() as Promise<FormSentryResponse>;
}
async function verifyWithRetry(payload, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://api.formsentry.ai/v1/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: process.env.FORMSENTRY_API_KEY,
formId: process.env.FORMSENTRY_FORM_ID,
payload
}),
signal: AbortSignal.timeout(5000)
});
if (response.ok) return response.json();
if (response.status === 429 || response.status >= 500) {
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw new Error(`FormSentry error: ${response.status}`);
} catch (error) {
if (attempt === maxRetries) throw error;
}
}
}

See Errors for all error codes and retry strategies.