API Reference
Complete API documentation for the Keverd fraud detection platform. All endpoints, request/response formats, error handling, and integration examples.
API Overview
Base URL
https://api.keverd.comAuthentication
All API requests require authentication using an API key. Include your API key in one of the following headers:
x-keverd-key(recommended)X-API-KEYAuthorization: Bearer YOUR_API_KEY
Content Type
All requests must use Content-Type: application/json
SDK Source Identification
SDKs automatically include the X-SDK-Source header to identify the SDK type:
javascript- Vanilla JavaScript SDKreact- React SDKvue- Vue.js SDKangular- Angular SDKandroid- Android SDK
/fingerprint/score
Score a fingerprint submission and return risk assessment. This is the primary endpoint for fraud detection. Accepts both SDK format (nested structure) and direct format (flat structure). Target latency: <100ms p99.
Request Format
SDK Format (Recommended)
This is the format used by all Keverd SDKs. It provides a structured, nested format that's easier to work with.
POST https://api.keverd.com/fingerprint/score
Content-Type: application/json
x-keverd-key: your-api-key-here
X-SDK-Source: javascript
{
"userId": "user123",
"device": {
"deviceId": "abc123...",
"fingerprint": "sha256_hash_64_chars...",
"manufacturer": "Apple",
"model": "iPhone 13",
"brand": "Apple",
"device": "mobile",
"product": "iPhone",
"hardware": "iPhone13,2",
"sdkVersion": "1.0.0",
"osVersion": "15.0",
"screenWidth": "390",
"screenHeight": "844",
"screenDensity": "3.0",
"locale": "en-US",
"timezone": "America/New_York"
},
"session": {
"sessionId": "session_123",
"timestamp": "2025-01-15T10:30:00Z"
},
"behavioral": {
"typing_dwell_ms": [120.5, 135.2, 110.8, 125.3, 130.1],
"typing_flight_ms": [45.2, 50.1, 42.3, 48.7, 46.5],
"swipe_velocity": 2.5,
"session_entropy": 3.8
}
}Android SDK Format (with SIM data)
Android SDK includes SIM card information for enhanced fraud detection:
{
"userId": "user123",
"device": {
"deviceId": "abc123...",
"fingerprint": "sha256_hash...",
"manufacturer": "Samsung",
"model": "SM-G991B",
"osVersion": "13",
"timezone": "Africa/Nairobi",
...
},
"sim": {
"simOperator": "63902",
"simOperatorName": "Safaricom",
"simSerialNumber": "hashed_sim_serial",
"networkOperator": "63902",
"networkType": "LTE"
},
"session": {
"sessionId": "session_123",
"sessionCount": "5",
"firstSession": "2025-01-01T00:00:00Z"
},
"behavioral": {
"typing_dwell_ms": [120.5, 135.2],
"typing_flight_ms": [45.2, 50.1],
"swipe_velocity": 2.5,
"session_entropy": 3.8
}
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | No | User identifier. If not provided, backend auto-generates from device fingerprint |
| device | object | Yes | Device information object (see DeviceInfo below) |
| session | object | No | Session information object (see SessionInfo below) |
| behavioral | object | No | Behavioral data object (see BehavioralData below) |
| sim | object | No | SIM card information (Android/iOS only, see SimInfo below) |
DeviceInfo Object
| Field | Type | Required | Description |
|---|---|---|---|
| deviceId | string | Yes | Unique device identifier (first 32 chars of fingerprint) |
| fingerprint | string | Yes | SHA-256 hash of device characteristics (64 hex characters) |
| manufacturer | string | No | Device manufacturer (e.g., "Apple", "Samsung") |
| model | string | No | Device model name |
| osVersion | string | No | Operating system version |
| screenWidth | string | No | Screen width in pixels |
| screenHeight | string | No | Screen height in pixels |
| timezone | string | Yes | IANA timezone identifier (e.g., "America/New_York", "Africa/Nairobi") |
| locale | string | No | Device locale (e.g., "en-US", "sw-KE") |
SessionInfo Object
| Field | Type | Description |
|---|---|---|
| sessionId | string | Unique session identifier |
| timestamp | string (ISO 8601) | Session timestamp in ISO 8601 format |
| sessionCount | string | Number of sessions for this device (Android SDK) |
| firstSession | string (ISO 8601) | Timestamp of first session (Android SDK) |
BehavioralData Object
| Field | Type | Description |
|---|---|---|
| typing_dwell_ms | number[] | Array of typing dwell times (time key is held down) in milliseconds. Typically 5-20 samples. |
| typing_flight_ms | number[] | Array of typing flight times (time between key releases) in milliseconds. Typically 5-20 samples. |
| swipe_velocity | number | Average swipe velocity in pixels per millisecond. 0.0 if no swipe data available. |
| session_entropy | number | Session entropy value (Shannon entropy) based on event diversity. Higher values indicate more diverse user interactions. 0.0 if no events collected. |
Enhanced Signals (Automatically Collected)
The SDK automatically collects enhanced behavioral signals that are critical for accurate risk scoring, especially for registration use cases. These signals are included automatically in all requests - you don't need to manually collect or send them.
Automatic Collection
All enhanced signals are collected automatically in the background from the moment the SDK is initialized. No manual collection or configuration is required.
Mouse Signals
| Field | Type | Description |
|---|---|---|
| clickCount | number | Total number of mouse clicks detected |
| totalDistance | number | Total distance mouse moved in pixels |
| averageVelocity | number | Average mouse movement velocity (pixels/ms) |
Used for: Detecting uniform mouse patterns (bot behavior), measuring user engagement, identifying automation
Keyboard Signals
| Field | Type | Description |
|---|---|---|
| keydownCount | number | Total number of keydown events |
| typingSpeed | number | Average typing speed (characters per second) |
Used for: Detecting uniform typing patterns (bot behavior), identifying copy-paste behavior, measuring typing consistency
Page Interactions
| Field | Type | Description |
|---|---|---|
| clickCount | number | Total page clicks |
| scrollDepth | number | Maximum scroll depth (0-100%) |
| timeToFirstInteraction | number | Time to first user interaction in milliseconds |
| timeOnPage | number | Total time spent on page in milliseconds |
Used for: Detecting minimal interactions (bot behavior), measuring engagement, identifying fast flows
Form Interactions
| Field | Type | Description |
|---|---|---|
| focusCount | number | Number of form field focus events |
| pasteCount | number | Number of paste events (high risk for registration) |
| autofillDetected | boolean | Whether browser autofill was detected |
| fieldFocusOrder | string[] | Order in which fields were focused (detects perfect completion) |
Used for: Detecting copy-paste behavior, identifying perfect form completion (bot), measuring form interaction patterns
Privacy Signals
| Field | Type | Description |
|---|---|---|
| isIncognito | boolean | Whether browser is in incognito/private mode |
| isVPN | boolean | Whether VPN or proxy is detected |
| isAutomated | boolean | Whether automation/bot is detected (high risk) |
| hasAdBlocker | boolean | Whether ad blocker is detected |
Used for: Detecting automation tools, identifying privacy-focused users, flagging suspicious browser configurations
Why These Signals Matter for Registration
- Bot Detection: Uniform mouse/keyboard patterns indicate automation
- Behavior Change: Mid-session changes suggest session hijacking or account sharing
- Copy-Paste Detection: Excessive paste events suggest fake account creation
- Perfect Completion: Forms filled too quickly or perfectly indicate bots
- Minimal Interactions: Low click/scroll counts suggest non-human behavior
Response Format
{
"risk_score": 25,
"score": 0.25,
"action": "allow",
"reason": [],
"session_id": "123e4567-e89b-12d3-a456-426614174000",
"requestId": "123e4567-e89b-12d3-a456-426614174000",
"sim_swap_engine": {
"risk": 0.0,
"flags": {
"sim_changed": false,
"device_changed": false,
"behavior_anomaly": false,
"time_anomaly": false,
"velocity_anomaly": false
},
"updatedProfile": {}
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| risk_score | number (0-100) | Risk score from 0 (lowest risk) to 100 (highest risk). Integer value for easy comparison. |
| score | number (0.0-1.0) | Normalized risk score as float. Equal to risk_score / 100. Provided for SDK compatibility. |
| action | string | Recommended action: "allow", "soft_challenge", "hard_challenge", or "block" |
| reason | string[] | Array of risk reasons explaining why the risk score was assigned. Examples: ["new_user_profile", "geo_jump", "device_changed", "behavior_anomaly"] |
| session_id | string (UUID) | Unique session identifier for this request. Use this to track and correlate events. |
| requestId | string (UUID) | Unique request identifier. Same as session_id, provided for SDK compatibility. |
| sim_swap_engine | object | SIM swap detection results (only present for Android/iOS SDKs with SIM data). Contains risk score and flags indicating detected anomalies. |
Risk Score Interpretation
Understanding Risk Scores: Risk scores are calculated based on multiple factors including device history, behavioral patterns, geographic anomalies, and SIM swap detection (for mobile devices).
| Score Range | Action | Meaning | Recommended Response |
|---|---|---|---|
| 0-29 | allow | Low risk. User appears to be legitimate based on device history and behavior patterns. | Proceed with login/transaction. No additional verification required. |
| 30-49 | soft_challenge | Moderate risk. Some anomalies detected but may be legitimate (e.g., new device, location change). | Require additional verification such as email/SMS verification or security questions. |
| 50-69 | hard_challenge | High risk. Significant anomalies detected (e.g., device change, behavioral mismatch, geographic jump). | Require strong MFA (multi-factor authentication) such as TOTP, hardware key, or biometric verification. |
| 70-100 | block | Very high risk. Strong indicators of fraud or account takeover (e.g., SIM swap, multiple device changes, suspicious behavior). | Block the request and flag for manual review. Consider account lockout and user notification. |
Risk Reasons
The reason array contains strings explaining why a particular risk score was assigned. Common reasons include:
Profile Reasons
new_user_profile- First time seeing this userdevice_changed- Different device than usualmultiple_devices- User has multiple devices
Geographic Reasons
geo_jump- Unusual location changevpn_detected- VPN or proxy detectedunusual_location- Location not in user history
Behavioral Reasons
behavior_anomaly- Typing patterns don't matchtyping_speed_mismatch- Typing speed differs significantlysession_entropy_low- Unusual interaction patterns
SIM Swap Reasons
sim_changed- SIM card changed (Android only)time_anomaly- Unusual timing patternsvelocity_anomaly- Rapid successive requests
Use-Case Verification Endpoints
These endpoints are optimized for specific use cases and automatically set the use_case parameter. They accept the same request format as /fingerprint/score and return the same response format.
/fingerprint/verify/login
Verify user identity during login attempts. Optimized for detecting account takeover and credential stuffing.
Use Case: Automatically set to "login"
/fingerprint/verify/checkout
Verify user during checkout/payment flows. Detects payment fraud and stolen card usage.
Use Case: Automatically set to "checkout"
/fingerprint/verify/registration
Verify new account registrations. Detects bot signups and fake accounts.
Use Case: Automatically set to "registration"
/fingerprint/verify/password-reset
Verify password reset requests. High-risk use case requiring enhanced security checks.
Use Case: Automatically set to "password_reset"
/fingerprint/verify/account-change
Verify account modification requests (email change, phone change, etc.).
Use Case: Automatically set to "account_change"
Registration Behavioral Monitoring
Overview
The registration verification endpoint provides continuous behavioral monitoring from the moment a user starts the registration process. This enables real-time detection of bot signups, behavior changes, and suspicious patterns.
Key Features:
- Automatic Baseline: SDK automatically establishes behavioral baseline from first interactions
- Mid-Session Detection: Detects behavior changes within a single registration session
- Enhanced Bot Detection: Identifies bots, automation, uniform patterns, and non-human behavior
- Adaptive Responses: Recommends MFA, CAPTCHA, or custom flows based on real-time risk
- Comprehensive Data Collection: Automatically collects mouse, keyboard, page, and form interactions
How It Works
The SDK automatically collects comprehensive behavioral data from the moment it's initialized. No manual data collection is required - everything happens automatically in the background.
1. Automatic Data Collection
When you initialize the SDK, it immediately starts collecting behavioral data automatically:
- Mouse movements: Velocity, acceleration, click patterns, movement distance
- Keyboard patterns: Typing speed, dwell time (key hold duration), flight time (time between keys)
- Page interactions: Clicks, scrolls, time on page, scroll depth
- Form interactions: Focus events, copy/paste detection, autofill detection, field focus order
- Privacy signals: Incognito mode, VPN detection, automation detection, ad blocker
// Initialize SDK early (e.g., on page load)
import { Keverd } from '@keverdjs/fraud-sdk';
// SDK automatically starts collecting data
Keverd.init('your-api-key');
// No additional setup required - data collection happens automaticallyThe SDK establishes a behavioral baseline automatically from the first interactions. This baseline is used to detect behavior changes during registration.
2. Registration Verification
Call the registration verification endpoint when the user submits the registration form. The SDK automatically includes all collected behavioral data.
// JavaScript SDK - Complete registration flow
import { Keverd } from '@keverdjs/fraud-sdk';
// Initialize early (e.g., in your app entry point)
Keverd.init('your-api-key');
// Later, when user submits registration form
async function handleRegistrationSubmit(formData) {
// Verify registration - SDK automatically includes all collected data
const result = await Keverd.verifyRegistration({
email: formData.email,
username: formData.username
});
// Handle response based on risk level
if (result.action === 'allow') {
// Low risk - proceed with registration
await createUserAccount(formData);
} else if (result.action === 'soft_challenge') {
// Medium risk - show recommended challenges
const challenges = result.adaptive_response?.challenges || [];
if (challenges.includes('captcha')) {
await showCaptcha();
}
if (challenges.includes('mfa')) {
await sendEmailVerification(formData.email);
}
} else if (result.action === 'block') {
// High risk - block registration
showError('Registration blocked due to security concerns');
}
}
// React SDK
import { useKeverdContext } from '@keverdjs/fraud-sdk-react';
function RegistrationForm() {
const { verifyRegistration } = useKeverdContext();
const handleSubmit = async (formData) => {
const result = await verifyRegistration({
email: formData.email,
username: formData.username
});
// Handle result...
};
}3. Session Management
The SDK automatically maintains a session ID that links all events together. Session continuity is maintained throughout the registration flow without any manual intervention.
// Session is automatically managed by SDK
// All events in the same session are linked
// Session persists from SDK init to page unload
// No manual session management requiredData Automatically Collected
The SDK automatically collects all the following data - you don't need to manually send anything:
Device Information
- • Screen resolution
- • Timezone
- • Language/locale
- • User agent
- • Device fingerprint
Mouse Signals
- • Click count
- • Movement distance
- • Average velocity
- • Movement patterns
Keyboard Signals
- • Typing speed
- • Keydown count
- • Dwell time (key hold)
- • Flight time (between keys)
Page Interactions
- • Click count
- • Scroll depth
- • Time to first interaction
- • Time on page
Form Interactions
- • Focus/blur events
- • Copy/paste detection
- • Autofill detection
- • Field focus order
Privacy Signals
- • Incognito mode
- • VPN/proxy detection
- • Automation detection
- • Ad blocker detection
All data collection is automatic
You don't need to manually collect or send any of this data. The SDK handles everything automatically when you call verifyRegistration().
Response Format
The registration verification endpoint returns enhanced response data including behavioral analysis:
{
"risk_score": 45,
"action": "soft_challenge",
"reason": [
"behavior_shift_detected",
"typing_speed_changed",
"uniform_typing_pattern"
],
"session_id": "session-uuid",
"request_id": "request-uuid",
"score": 0.45,
// Behavioral change analysis
"behavior_change": {
"baseline_available": true,
"behavior_changed": true,
"change_score": 35.5,
"change_reasons": [
"typing_speed_changed",
"mouse_pattern_changed"
],
"similarity_score": 62.3
},
// Adaptive response recommendations
"adaptive_response": {
"recommended_action": "soft_challenge",
"challenges": ["mfa", "captcha"],
"reason": "Behavior change detected during registration",
"confidence": 0.85
}
}Adaptive Responses
Understanding Adaptive Responses
Based on real-time risk assessment and behavioral analysis, the API recommends specific actions to take. You should implement these recommendations to create an adaptive registration flow.
Allow (Low Risk)
action: "allow" - Registration appears legitimate. Proceed with account creation.
if (result.action === "allow") {
// Proceed with registration
await createUserAccount(userData);
}Soft Challenge (Medium Risk)
action: "soft_challenge" - Some suspicious signals detected. Require additional verification.
if (result.action === "soft_challenge") {
// Check adaptive_response for recommended challenges
const challenges = result.adaptive_response?.challenges || [];
if (challenges.includes("captcha")) {
// Show CAPTCHA
await showCaptcha();
}
if (challenges.includes("mfa")) {
// Request email/SMS verification
await sendVerificationCode(userEmail);
}
// After challenge completion, verify again
const recheck = await keverd.verifyRegistration();
if (recheck.action === "allow") {
await createUserAccount(userData);
}
}Hard Challenge (High Risk)
action: "hard_challenge" - Multiple suspicious signals. Require strong verification.
if (result.action === "hard_challenge") {
// Require multiple verification steps
await showCaptcha();
await sendVerificationCode(userEmail);
await sendVerificationCode(userPhone);
// Verify all challenges passed
const allVerified = await verifyAllChallenges();
if (allVerified) {
const recheck = await keverd.verifyRegistration();
if (recheck.action === "allow") {
await createUserAccount(userData);
}
}
}Block (Very High Risk)
action: "block" - Clear bot or fraud indicators. Block registration.
if (result.action === "block") {
// Block registration
showError("Registration blocked due to security concerns");
// Optionally log for review
logSuspiciousRegistration(result);
}Behavior Change Indicators
The behavior_change object provides detailed information about behavioral anomalies:
baseline_available
Whether a behavioral baseline exists (automatically established from first interactions)
behavior_changed
Whether behavior deviated from baseline during the session
change_score
0-100 score indicating severity of behavior change (higher = more suspicious)
similarity_score
0-100 percentage similarity to baseline (higher = more similar, lower = more suspicious)
change_reasons
List of specific reasons for behavior change (e.g., "typing_speed_changed", "mouse_pattern_changed")
Complete Integration Example
// React example
import { useKeverdContext } from '@keverdjs/fraud-sdk-react';
function RegistrationForm() {
const { verifyRegistration } = useKeverdContext();
const [step, setStep] = useState('form');
const handleSubmit = async (formData) => {
try {
// Verify registration with behavioral monitoring
const result = await verifyRegistration({
email: formData.email,
username: formData.username
});
// Check risk level
if (result.action === "block") {
// Block registration
showError("Registration blocked. Please contact support.");
return;
}
if (result.action === "hard_challenge") {
// Require multiple verifications
setStep('challenge');
await showCaptcha();
await sendEmailVerification(formData.email);
await sendSMSVerification(formData.phone);
return;
}
if (result.action === "soft_challenge") {
// Check recommended challenges
const challenges = result.adaptive_response?.challenges || [];
if (challenges.includes("captcha")) {
await showCaptcha();
}
if (challenges.includes("mfa")) {
await sendEmailVerification(formData.email);
}
// Re-verify after challenges
const recheck = await verifyRegistration();
if (recheck.action !== "allow") {
showError("Verification failed. Please try again.");
return;
}
}
// Behavior change detected?
if (result.behavior_change?.behavior_changed) {
console.warn("Behavior change detected:", result.behavior_change.change_reasons);
// Log for review or require additional verification
if (result.behavior_change.change_score > 50) {
await sendEmailVerification(formData.email);
}
}
// Proceed with registration
await createUserAccount(formData);
showSuccess("Account created successfully!");
} catch (error) {
console.error("Registration verification failed:", error);
showError("Registration failed. Please try again.");
}
};
return (
// Your registration form JSX
);
}Use Case Integration Examples
Registration Flow
Complete registration flow with behavioral monitoring, bot detection, and adaptive challenges.
Vanilla JavaScript
import { Keverd } from '@keverdjs/fraud-sdk';
// 1. Initialize SDK early (e.g., in your app entry point)
Keverd.init('your-api-key');
// 2. Registration form handler
async function handleRegistrationSubmit(formData) {
try {
// Verify registration - SDK automatically includes all collected data
const result = await Keverd.verifyRegistration({
email: formData.email,
username: formData.username
});
// Handle based on risk level
if (result.action === 'block') {
// High risk - block registration
showError('Registration blocked due to security concerns');
logSecurityEvent('blocked_registration', result);
return;
}
if (result.action === 'hard_challenge') {
// High risk - require multiple verifications
await showCaptcha();
await sendEmailVerification(formData.email);
await sendSMSVerification(formData.phone);
// Re-verify after challenges
const recheck = await Keverd.verifyRegistration();
if (recheck.action !== 'allow') {
showError('Verification failed. Please contact support.');
return;
}
}
if (result.action === 'soft_challenge') {
// Medium risk - show recommended challenges
const challenges = result.adaptive_response?.challenges || [];
if (challenges.includes('captcha')) {
const captchaValid = await showCaptcha();
if (!captchaValid) {
showError('CAPTCHA verification failed');
return;
}
}
if (challenges.includes('mfa')) {
await sendEmailVerification(formData.email);
}
// Re-verify after challenges
const recheck = await Keverd.verifyRegistration();
if (recheck.action !== 'allow') {
showError('Verification failed. Please try again.');
return;
}
}
// Check for behavior changes
if (result.behavior_change?.behavior_changed) {
console.warn('Behavior change detected:', result.behavior_change.change_reasons);
// Log for review or require additional verification
if (result.behavior_change.change_score > 50) {
await sendEmailVerification(formData.email);
}
}
// All checks passed - create account
const account = await createUserAccount(formData);
showSuccess('Account created successfully!');
return account;
} catch (error) {
console.error('Registration verification failed:', error);
showError('Registration failed. Please try again.');
}
}React
import { useKeverdContext } from '@keverdjs/fraud-sdk-react';
function RegistrationForm() {
const { verifyRegistration } = useKeverdContext();
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
const formData = {
email: e.target.email.value,
username: e.target.username.value,
password: e.target.password.value
};
try {
const result = await verifyRegistration({
email: formData.email,
username: formData.username
});
if (result.action === 'block') {
setError('Registration blocked. Please contact support.');
return;
}
if (result.action === 'soft_challenge' || result.action === 'hard_challenge') {
const challenges = result.adaptive_response?.challenges || [];
// Show challenges based on recommendations
if (challenges.includes('captcha')) {
await showCaptcha();
}
if (challenges.includes('mfa')) {
await sendEmailVerification(formData.email);
}
// Re-verify
const recheck = await verifyRegistration();
if (recheck.action !== 'allow') {
setError('Verification failed.');
return;
}
}
// Create account
await createAccount(formData);
router.push('/dashboard');
} catch (error) {
setError('Registration failed. Please try again.');
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
{/* Your form fields */}
</form>
);
}Vue.js
<script setup>
import { useKeverdProvider } from '@keverdjs/fraud-sdk-vue';
const { verifyRegistration } = useKeverdProvider();
const loading = ref(false);
const error = ref(null);
const handleSubmit = async (formData) => {
loading.value = true;
error.value = null;
try {
const result = await verifyRegistration({
email: formData.email,
username: formData.username
});
if (result.action === 'block') {
error.value = 'Registration blocked. Please contact support.';
return;
}
if (result.action !== 'allow') {
const challenges = result.adaptive_response?.challenges || [];
// Handle challenges...
}
await createAccount(formData);
router.push('/dashboard');
} catch (err) {
error.value = 'Registration failed. Please try again.';
} finally {
loading.value = false;
}
};
</script>Login Flow
Detect account takeover attempts and credential stuffing during login.
import { Keverd } from '@keverdjs/fraud-sdk';
async function handleLogin(email, password) {
try {
// Verify login attempt
const result = await Keverd.verifyLogin(email);
if (result.action === 'block') {
// Block login - potential account takeover
showError('Login blocked due to security concerns');
logSecurityEvent('blocked_login', { email, result });
return;
}
// Proceed with authentication
const authResult = await authenticateUser(email, password);
if (!authResult.success) {
return;
}
// If high risk, require MFA even after successful password
if (result.action === 'hard_challenge') {
const mfaValid = await requestMFA();
if (!mfaValid) {
showError('MFA verification failed');
return;
}
}
// Login successful
redirectToDashboard();
} catch (error) {
console.error('Login verification failed:', error);
showError('Login failed. Please try again.');
}
}Checkout Flow
Verify payment transactions and detect payment fraud.
import { Keverd } from '@keverdjs/fraud-sdk';
async function handleCheckout(cart, paymentMethod) {
try {
// Verify checkout
const result = await Keverd.verifyCheckout(
cart.total,
cart.currency,
{
paymentMethod: paymentMethod.type,
cardLast4: paymentMethod.last4,
items: cart.items.length
}
);
if (result.action === 'block') {
// Block transaction
showError('Transaction blocked due to security concerns');
logSecurityEvent('blocked_transaction', { amount: cart.total, result });
return;
}
if (result.action === 'hard_challenge') {
// Require payment verification
const verified = await requestPayment2FA();
if (!verified) {
showError('Payment verification failed');
return;
}
}
// Proceed with payment
const paymentResult = await processPayment(cart, paymentMethod);
if (paymentResult.success) {
showSuccess('Payment processed successfully!');
}
} catch (error) {
console.error('Checkout verification failed:', error);
showError('Payment failed. Please try again.');
}
}Password Reset Flow
Detect account takeover attempts during password reset requests.
import { Keverd } from '@keverdjs/fraud-sdk';
async function handlePasswordReset(email) {
try {
// Verify password reset request
const result = await Keverd.verifyPasswordReset(email);
if (result.action === 'block') {
// Block password reset - potential account takeover
showError('Password reset blocked. Please contact support.');
logSecurityEvent('blocked_password_reset', { email, result });
return;
}
if (result.action === 'hard_challenge') {
// Require additional verification
const verified = await sendVerificationCode(email);
if (!verified) {
showError('Verification failed');
return;
}
}
// Send password reset email
await sendPasswordResetEmail(email);
showSuccess('Password reset email sent!');
} catch (error) {
console.error('Password reset verification failed:', error);
showError('Password reset failed. Please try again.');
}
}Account Change Flow
Verify sensitive account modifications (email, phone, password changes).
import { Keverd } from '@keverdjs/fraud-sdk';
async function handleEmailChange(currentEmail, newEmail) {
try {
// Verify account change
const result = await Keverd.verifyAccountChange('email', {
oldEmail: currentEmail,
newEmail: newEmail
});
if (result.action === 'block') {
showError('Email change blocked. Please contact support.');
return;
}
if (result.action === 'hard_challenge') {
// Require verification from both emails
await sendVerificationCode(currentEmail);
await sendVerificationCode(newEmail);
const bothVerified = await verifyBothCodes();
if (!bothVerified) {
showError('Verification failed');
return;
}
}
// Proceed with email change
await updateUserEmail(newEmail);
showSuccess('Email updated successfully!');
} catch (error) {
console.error('Account change verification failed:', error);
showError('Email change failed. Please try again.');
}
}Error Handling
HTTP Status Codes
| Status Code | Meaning | Response Body |
|---|---|---|
| 200 | Success | FingerprintScoreResponse object |
| 400 | Bad Request | Error message describing invalid request format or missing required fields |
| 401 | Unauthorized | Invalid or missing API key |
| 403 | Forbidden | API key inactive or insufficient permissions |
| 429 | Too Many Requests | Rate limit exceeded. Check Retry-After header |
| 500 | Internal Server Error | Server error. Retry request after a delay |
Error Response Format
{
"detail": "Error message describing what went wrong",
"error_code": "ERROR_CODE",
"status_code": 400
}Common Error Codes
INVALID_API_KEY
The provided API key is invalid or has been revoked.
MISSING_DEVICE_INFO
Required device information is missing from the request.
RATE_LIMIT_EXCEEDED
Too many requests. Rate limit is 100 requests per second per API key.
INVALID_FINGERPRINT
Device fingerprint format is invalid. Must be SHA-256 hash (64 hex characters).
Authentication
All API requests require authentication using an API key. You can obtain your API key from the API Keys page in the dashboard.
Header Format
Include your API key in the request headers. The API accepts multiple header formats for compatibility:
# Recommended format
x-keverd-key: your-api-key-here
# Alternative formats (also supported)
X-API-KEY: your-api-key-here
Authorization: Bearer your-api-key-hereSecurity Note: Never expose your API key in client-side code or commit it to version control. Always use environment variables or secure configuration management.
Rate Limiting
Rate Limits
- Per API Key: 100 requests per second
- Per User ID: 100 requests per second (additional limit)
- Sandbox Environment: 10 requests per second
Rate Limit Headers
When rate limits are approached or exceeded, the API includes the following headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum number of requests allowed per window |
| X-RateLimit-Remaining | Number of requests remaining in current window |
| X-RateLimit-Reset | Unix timestamp when rate limit resets |
| Retry-After | Seconds to wait before retrying (only on 429 responses) |
Best Practice: Implement exponential backoff when receiving 429 responses. Start with a 1-second delay and double it for each subsequent retry, up to a maximum of 60 seconds.
Code Examples
cURL Example
curl -X POST https://api.keverd.com/fingerprint/score \
-H "Content-Type: application/json" \
-H "x-keverd-key: your-api-key-here" \
-d '{
"userId": "user123",
"device": {
"deviceId": "abc123",
"fingerprint": "sha256_hash_64_chars...",
"timezone": "America/New_York"
},
"behavioral": {
"typing_dwell_ms": [120.5, 135.2, 110.8],
"typing_flight_ms": [45.2, 50.1, 42.3],
"swipe_velocity": 2.5,
"session_entropy": 3.8
}
}'JavaScript/Fetch Example
const response = await fetch('https://api.keverd.com/fingerprint/score', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-keverd-key': 'your-api-key-here'
},
body: JSON.stringify({
userId: 'user123',
device: {
deviceId: 'abc123',
fingerprint: 'sha256_hash...',
timezone: 'America/New_York'
},
behavioral: {
typing_dwell_ms: [120.5, 135.2, 110.8],
typing_flight_ms: [45.2, 50.1, 42.3],
swipe_velocity: 2.5,
session_entropy: 3.8
}
})
});
const data = await response.json();
console.log('Risk Score:', data.risk_score);
console.log('Action:', data.action);Python Example
import requests
url = "https://api.keverd.com/fingerprint/score"
headers = {
"Content-Type": "application/json",
"x-keverd-key": "your-api-key-here"
}
payload = {
"userId": "user123",
"device": {
"deviceId": "abc123",
"fingerprint": "sha256_hash...",
"timezone": "America/New_York"
},
"behavioral": {
"typing_dwell_ms": [120.5, 135.2, 110.8],
"typing_flight_ms": [45.2, 50.1, 42.3],
"swipe_velocity": 2.5,
"session_entropy": 3.8
}
}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
print(f"Risk Score: {data['risk_score']}")
print(f"Action: {data['action']}")Performance & Latency
Target Performance
- p50 Latency: < 50ms (median response time)
- p95 Latency: < 80ms (95th percentile)
- p99 Latency: < 100ms (99th percentile)
Optimization Tips
- • Use connection pooling for multiple requests
- • Implement request batching when possible
- • Cache risk scores for short periods (5-10 seconds) for repeated requests
- • Use async/await or non-blocking I/O for better concurrency
Data Privacy & Compliance
Privacy-First Design
- All device identifiers are SHA-256 hashed client-side before transmission
- No raw PII (Personally Identifiable Information) is stored or transmitted
- HTTPS-only communication enforced
- GDPR and Kenya Data Protection Act compliant
Data Retention
Fingerprint data is retained according to your subscription plan and regional compliance requirements. You can request data deletion through the dashboard or API.
SDK Integration Guides
For easier integration, use one of our official SDKs which handle all the API details for you: