Built against OWASP LLM01Benchmark re-run every 6 hoursOpen-source SDK · MIT

Quick Start Guide

Check one input, enforce the verdict, then test failures before connecting your model.

1. Get Your API Key

Sign up, confirm your email, then get your API key from dashboard.safeprompt.dev

2. Install the SDK (Optional)

Use the official npm package for a typed client, or call the HTTP API directly. The published JavaScript SDK uses the API default, balanced; the raw HTTP examples below explicitly send strict.

npm install safeprompt
import SafePrompt from 'safeprompt';

const sp = new SafePrompt({ apiKey: 'YOUR_API_KEY' });

const result = await sp.check(userInput, { userIP: clientIP });
if (typeof result.safe !== 'boolean' || !result.safe) {
  throw new Error('Unsafe or invalid verdict');
}
// Only now add this checked input to model context.

The SDK forwards the userIP you supply. Keep the key on your server. The raw HTTP helper gives you explicit sensitivity control and a configurable request deadline without a package.

3. Validate User Prompts

async function validatePrompt(userInput, clientIpAddress, timeoutMs) {
  const response = await fetch('https://api.safeprompt.dev/api/v1/validate', {
  method: 'POST',
  headers: {
    'X-API-Key': 'YOUR_API_KEY',
    'X-User-IP': clientIpAddress, // End user's IP address
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ prompt: userInput, sensitivity: 'strict' }),
  signal: AbortSignal.timeout(timeoutMs)
});

if (!response.ok) throw new Error('Validation HTTP error');
const result = await response.json();
if (typeof result.safe !== 'boolean' || !result.safe) {
  throw new Error('Unsafe or invalid verdict');
}
return result; // Forward the same checked input only after this resolves.
}

4. Understanding the Response

The following is an illustrative response shape, not an observed attack result. Require successful HTTP status and a boolean safe before using any verdict.

  • safe (boolean): true is a passing verdict for submitted text; false tells your app to stop it
  • confidence (float, 0-1): Detector confidence, not a calibrated attack probability or permission grant
  • threats (array): List of detected threat types (e.g., "jailbreak_instruction_override", "jailbreak")
  • processingTime (number): Response time in milliseconds
{
  "safe": false,
  "confidence": 0.95,
  "threats": ["jailbreak_instruction_override"],
  "reasoning": "Illustrative instruction-override verdict",
  "sessionToken": null
}

5. Important: End User IP Address

Always pass the end user's IP address via the X-User-IP header, not your server's IP.

Derive the address through trusted server configuration:

  • Express.js: use req.ip after configuring trust proxy for your actual proxy topology
  • Flask/Django: use the framework's client address after configuring trusted proxies
  • Next.js: use the client address supplied by your trusted deployment platform
  • PHP: use the verified client address supplied by your trusted server or proxy

For testing and development:

Use documentation addresses only in local mocks. In production, supply the actual end user address; a server address or test placeholder does not meet that requirement. The request below shows the shape and is not a recommendation to send a fabricated address to the live API.

# Documentation placeholder; replace with the actual end user IP before live use
curl -X POST https://api.safeprompt.dev/api/v1/validate \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-User-IP: 203.0.113.45" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Hello world", "sensitivity": "strict"}'

Why X-User-IP is required:

  • Threat intelligence: Supplies correlation signals from submitted requests
  • IP reputation: Identifies patterns of malicious behavior
  • Network defense: Supplies correlation signals; a verdict does not guarantee protection elsewhere

6. Best Practices

Stop Unavailable Checks

Use the validatePrompt HTTP helper in the JavaScript tab above. If a check fails, keep the input out of model context. Retry or return an error. Continuing without a verdict explicitly bypasses screening. The snippets use a timeout budget you configure for your application; compare it with the published latency percentiles.

async function checkedInput(userInput, clientIP, timeoutMs) {
  const result = await validatePrompt(userInput, clientIP, timeoutMs);
  if (typeof result.safe !== 'boolean' || !result.safe) {
    throw new Error('Unsafe or invalid verdict');
  }
  return userInput; // Add to context only after this resolves.
}

Keep the Exact Input

Submit the same representation your model receives, including source labels. Avoid reusing a verdict keyed only by lowercased or trimmed text: IP, conversation context, sensitivity and detector changes can alter its meaning.

async function checkRetrievedText(extractedText, clientIP, timeoutMs) {
  // Include source labels here if the model will receive them too.
  const verdict = await validatePrompt(extractedText, clientIP, timeoutMs);
  if (typeof verdict.safe !== 'boolean' || !verdict.safe) {
    throw new Error('Unsafe or invalid verdict');
  }
  return extractedText; // Forward these same bytes, not another extraction.
}

Conversation Context

Keep the returned sessionToken with its conversation and send it as session_token on the next raw request. Sessions expire after two hours idle and at most 24 hours. Published payload-turn tests do not establish gradual escalation coverage.

// Keep this state per conversation and tenant, not in a shared global.
const conversation = { sessionToken: null };

async function validateConversationTurn(userInput, clientIP, conversation, timeoutMs) {
  const requestBody = {
    prompt: userInput,
    sensitivity: 'strict'
  };

  // Associate this check with this conversation only.
  if (conversation.sessionToken) {
    requestBody.session_token = conversation.sessionToken;
  }

  const result = await fetch('https://api.safeprompt.dev/api/v1/validate', {
    method: 'POST',
    headers: {
      'X-API-Key': 'YOUR_API_KEY',
      'X-User-IP': clientIP,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(requestBody),
    signal: AbortSignal.timeout(timeoutMs)
  });

  if (!result.ok) throw new Error('Validation HTTP error');
  const data = await result.json();
  if (typeof data.safe !== 'boolean' || !data.safe) {
    throw new Error('Unsafe or invalid verdict');
  }
  if (typeof data.sessionToken === 'string') {
    conversation.sessionToken = data.sessionToken;
  }
  return data;
}

Next Steps