Node.js SDK
Official TypeScript/JavaScript SDK for the NOPE API. Full type definitions included.
Package: @nope-net/sdk on npm
Installation
npm install @nope-net/sdk Client Initialization
import { NopeClient } from '@nope-net/sdk';
// Production client
const client = new NopeClient({
apiKey: 'nope_live_...',
timeout: 30000, // Optional: request timeout in ms (default: 30000)
baseUrl: 'https://api.nope.net', // Optional: custom API URL
});
// Demo mode (no API key required, uses /v1/try/* endpoints)
const demoClient = new NopeClient({
demo: true,
timeout: 30000,
}); Methods
evaluate()
Full risk assessment across all 9 risk types with clinical features, protective factors, and crisis resources. See Evaluate Guide for response semantics.
import { NopeClient } from '@nope-net/sdk';
const client = new NopeClient({ apiKey: 'nope_live_...' });
// With messages array
const result = await client.evaluate({
messages: [
{ role: 'user', content: "I've been feeling really down lately" },
{ role: 'assistant', content: "I'm sorry to hear that. Can you tell me more?" },
{ role: 'user', content: "I just feel hopeless, like nothing will get better" },
],
config: { user_country: 'US' },
});
console.log(result.summary.speaker_severity); // 'none' | 'mild' | 'moderate' | 'high' | 'critical'
console.log(result.summary.speaker_imminence); // 'not_applicable' | 'chronic' | 'subacute' | 'urgent' | 'emergency'
// With plain text
const textResult = await client.evaluate({
text: "Patient expressed feelings of hopelessness during session.",
config: { user_country: 'US' },
}); screen()
Lightweight crisis triage. Returns severity, imminence, and matched resources for all 9 risk types. See Screen Guide for response semantics.
const result = await client.screen({
messages: [{ role: 'user', content: "I don't want to be here anymore" }],
config: { country: 'US' },
});
if (result.show_resources) {
console.log('Crisis detected:', result.rationale);
console.log('Primary resource:', result.resources?.primary.name);
console.log('Call:', result.resources?.primary.phone);
}
// Access expanded risks array (all 9 risk types)
for (const risk of result.risks) {
console.log(`${risk.type}: ${risk.severity} (subject: ${risk.subject})`);
} oversight.analyze()
Analyze AI conversations for harmful behaviors (85 behavior types across 14 categories). See Oversight Guide and AI Behavior Taxonomy.
const result = await client.oversight.analyze({
conversation: {
conversation_id: 'conv_123',
messages: [
{ role: 'user', content: "I've been feeling really lonely lately" },
{ role: 'assistant', content: "I understand. I'm always here for you." },
{ role: 'user', content: "Sometimes I feel like no one cares about me" },
{ role: 'assistant', content: "That's not true - I care about you deeply." },
],
metadata: {
user_is_minor: false,
platform: 'my-app',
},
},
});
console.log('Concern level:', result.result.overall_concern); // 'none' | 'low' | 'medium' | 'high' | 'critical'
console.log('Trajectory:', result.result.trajectory); // 'improving' | 'stable' | 'worsening'
for (const behavior of result.result.detected_behaviors) {
console.log(` ${behavior.code}: ${behavior.severity}`);
} resources(), resourcesSmart(), resourcesCountries(), detectCountry()
Crisis resource lookup and AI-ranked recommendations. See Resources Guide and Service Taxonomy.
// Get crisis resources by country
const resources = await client.resources('US', {
scopes: ['suicide', 'crisis'],
urgent: true,
});
console.log(`Found ${resources.count} resources`);
for (const resource of resources.resources) {
console.log(` ${resource.name}: ${resource.phone}`);
}
// AI-ranked resources (requires demo mode or auth)
const ranked = await client.resourcesSmart('US', 'teen struggling with eating disorder');
for (const item of ranked.ranked) {
console.log(`${item.rank}. ${item.resource.name}`);
console.log(` Why: ${item.why}`);
}
// List supported countries
const countries = await client.resourcesCountries();
console.log('Supported:', countries.countries.join(', '));
// Detect user's country from request headers
const detected = await client.detectCountry();
console.log('Detected country:', detected.country_code); Error Handling
All errors extend the base NopeError class with statusCode and message properties.
import {
NopeClient,
NopeAuthError,
NopeValidationError,
NopeRateLimitError,
NopeServerError,
NopeConnectionError,
} from '@nope-net/sdk';
const client = new NopeClient({ apiKey: 'nope_live_...' });
try {
const result = await client.evaluate({
messages: [{ role: 'user', content: 'Hello' }],
});
} catch (error) {
if (error instanceof NopeAuthError) {
// 401: Invalid or missing API key
console.error('Auth failed:', error.message);
} else if (error instanceof NopeValidationError) {
// 400: Invalid request (missing fields, bad format)
console.error('Validation error:', error.message);
} else if (error instanceof NopeRateLimitError) {
// 429: Rate limit exceeded
console.error('Rate limited, retry after:', error.retryAfter, 'ms');
} else if (error instanceof NopeServerError) {
// 5xx: Server error
console.error('Server error:', error.statusCode);
} else if (error instanceof NopeConnectionError) {
// Network error (timeout, DNS, etc.)
console.error('Connection failed:', error.message);
}
} | Error Class | Status | When |
|---|---|---|
NopeAuthError | 401 | Invalid or missing API key |
NopeValidationError | 400 | Invalid request format |
NopeRateLimitError | 429 | Rate limit exceeded (retryAfter in ms) |
NopeServerError | 5xx | Server-side error |
NopeConnectionError | — | Network failure (timeout, DNS) |
Webhook Verification
Verify webhook signatures to ensure requests are from NOPE. See Webhooks Guide for setup.
import { Webhook, WebhookSignatureError } from '@nope-net/sdk';
const webhook = new Webhook('whsec_your_webhook_secret');
// In your webhook handler (Express, Hono, etc.)
app.post('/webhook', async (req, res) => {
const signature = req.headers['x-nope-signature'];
const timestamp = req.headers['x-nope-timestamp'];
const body = await req.text(); // raw body string
try {
const payload = webhook.verify(body, signature, timestamp, {
tolerance: 300, // Optional: max age in seconds (default: 300)
});
// payload is typed as WebhookPayload
switch (payload.event) {
case 'evaluate.alert':
console.log('Risk alert:', payload.risk_summary.speaker_severity);
break;
case 'oversight.alert':
console.log('AI concern:', payload.overall_concern);
break;
}
res.status(200).send('OK');
} catch (error) {
if (error instanceof WebhookSignatureError) {
console.error('Invalid signature');
res.status(401).send('Invalid signature');
}
}
}); TypeScript Types
All types are exported for use in your application:
import type {
// Client options
NopeClientOptions,
EvaluateOptions,
ScreenOptions,
// Response types
EvaluateResponse,
ScreenResponse,
OversightAnalyzeResponse,
ResourcesResponse,
// Core types
Risk,
Summary,
CrisisResource,
Severity,
Imminence,
RiskType,
RiskSubject,
// Screen types
ScreenRisk,
ScreenCrisisResources,
// Oversight types
OversightAnalysisResult,
DetectedBehavior,
// Webhook types
WebhookPayload,
WebhookEventType,
} from '@nope-net/sdk'; For type semantics (severity levels, risk types, etc.), see:
- User Risk Taxonomy — 9 risk types, severity/imminence scales
- AI Behavior Taxonomy — 87 Oversight behaviors
- Service Taxonomy — Resource scopes and populations
Utility Functions
Helper functions for working with risk assessments:
import {
calculateSpeakerSeverity,
calculateSpeakerImminence,
hasThirdPartyRisk,
SEVERITY_SCORES,
IMMINENCE_SCORES,
} from '@nope-net/sdk';
// Calculate aggregate severity from risks array
const severity = calculateSpeakerSeverity(result.risks);
// Check if any third-party risk exists
const hasThirdParty = hasThirdPartyRisk(result.risks);
// Severity/imminence as numeric scores for comparison
console.log(SEVERITY_SCORES.critical); // 4
console.log(IMMINENCE_SCORES.emergency); // 4