Backend API
Server-side API for validating sessions and making decisions
Backend API
The BotSigged Backend API allows your server to query session data and make decisions about account creation, purchases, authentication, and other sensitive actions.
Authentication
All API requests require your site’s API key in the Authorization header:
Authorization: Bearer your-site-api-key
Base URL
https://your-botsigged-instance.com/api/v1
Endpoints
Get Session Details
Retrieve full session information including bot score, classification, and triggered flags.
GET /api/v1/sessions/:session_id
Response:
{
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"bot_score": 25,
"classification": "human",
"is_bot": false,
"recommendation": "allow",
"triggered_flags": [],
"session_duration_seconds": 45,
"event_count": 234
}
Response Fields:
| Field | Type | Description |
|---|---|---|
session_id |
string | The session identifier |
bot_score |
integer | Risk score from 0-100 (higher = more bot-like) |
classification |
string | Behavioral classification (see below) |
is_bot |
boolean |
true if score >= 50 or classification indicates bot |
recommendation |
string |
Suggested action: allow, challenge, or block |
triggered_flags |
array | List of detection rules that fired |
session_duration_seconds |
integer | How long the session has been active |
event_count |
integer | Total behavioral events recorded |
Classifications:
| Category | Classifications | Description |
|---|---|---|
| Trusted |
human, search_engine, known_agent |
Allow without friction |
| Neutral |
scraper, headless_fetch, suspicious |
Consider verification |
| Malicious |
bad_bot, stealth_bot, bad_agent, bad_scraper, abusive_human |
Block or challenge |
Validate Session
Get a simple allow/block decision for a session.
POST /api/v1/sessions/:session_id/validate
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
threshold |
integer | 50 | Score threshold for blocking |
Response:
{
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"allow": true,
"reason": "passed_validation",
"bot_score": 25,
"threshold": 50
}
Response Fields:
| Field | Type | Description |
|---|---|---|
allow |
boolean |
true if request should proceed |
reason |
string | Why the decision was made |
bot_score |
integer | Current bot score |
threshold |
integer | Threshold used for decision |
Reasons:
| Reason | Description |
|---|---|
passed_validation |
Score below threshold and not a bot classification |
bot_score_exceeded_threshold |
Score at or above threshold |
bot_classification_detected |
Classification indicates malicious bot |
Example Integrations
Account Registration
Protect signups from automated account creation:
// Node.js/Express
app.post('/api/signup', async (req, res) => {
const sessionId = req.headers['x-botsigged-id'] || req.body._bsid;
if (!sessionId) {
return res.status(400).json({ error: 'Missing session' });
}
try {
// Use validate endpoint for simple decision
const validation = await fetch(
`${BOTSIGGED_API}/sessions/${sessionId}/validate?threshold=40`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
).then(r => r.json());
if (!validation.allow) {
// Log for review
await logBlockedSignup(req.body.email, sessionId, validation);
return res.status(403).json({
error: 'Unable to create account. Please try again later.',
});
}
// Create account
const user = await createUser(req.body);
return res.json({ success: true, userId: user.id });
} catch (error) {
// On API error, allow with logging (fail open)
console.error('BotSigged API error:', error);
const user = await createUser(req.body);
return res.json({ success: true, userId: user.id });
}
});
E-commerce Checkout
Prevent fraudulent purchases:
app.post('/api/checkout', async (req, res) => {
const sessionId = req.headers['x-botsigged-id'];
const { cart, paymentMethod } = req.body;
// Get full session details for fraud analysis
const session = await fetch(
`${BOTSIGGED_API}/sessions/${sessionId}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
).then(r => r.json());
// Block obvious bots
if (session.bot_score >= 70) {
return res.status(403).json({
error: 'Unable to process order. Please contact support.',
});
}
// Flag suspicious orders for manual review
if (session.bot_score >= 40 || session.classification === 'suspicious') {
await flagOrderForReview(cart, session);
}
// Additional checks for high-value orders
if (cart.total > 500 && session.bot_score >= 30) {
// Require additional verification
return res.json({
requiresVerification: true,
verificationType: 'phone',
});
}
// Process order
const order = await processOrder(cart, paymentMethod);
return res.json({ success: true, orderId: order.id });
});
Login Protection
Defend against credential stuffing:
app.post('/api/login', async (req, res) => {
const sessionId = req.headers['x-botsigged-id'];
const { email, password } = req.body;
const session = await fetch(
`${BOTSIGGED_API}/sessions/${sessionId}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
).then(r => r.json());
// Log all attempts for security analysis
await securityLog.create({
event: 'login_attempt',
email: hashEmail(email),
sessionId,
botScore: session.bot_score,
classification: session.classification,
triggeredFlags: session.triggered_flags,
ip: req.ip,
});
// Block high-risk attempts
if (session.is_bot || session.bot_score >= 80) {
return res.status(403).json({
error: 'Unable to sign in. Please try again later.',
});
}
// Validate credentials
const user = await validateCredentials(email, password);
if (!user) {
// Apply stricter rate limits for suspicious sessions
if (session.bot_score >= 40) {
await applyRateLimit(req.ip, 'strict');
}
return res.status(401).json({ error: 'Invalid email or password' });
}
// Successful login - check for account takeover indicators
if (session.bot_score >= 50 || session.triggered_flags.includes('is_automation_framework')) {
await notifyUserOfSuspiciousLogin(user, req);
}
const token = await createSession(user);
return res.json({ token });
});
Form Submission
Generic form protection:
app.post('/api/contact', async (req, res) => {
const sessionId = req.body._bsid;
const validation = await fetch(
`${BOTSIGGED_API}/sessions/${sessionId}/validate`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
).then(r => r.json());
if (!validation.allow) {
// Return success to avoid revealing detection
// but don't actually process the submission
console.log('Blocked spam submission:', sessionId);
return res.json({ success: true });
}
// Process legitimate submission
await sendContactEmail(req.body);
return res.json({ success: true });
});
Review/Comment Moderation
Automatic spam filtering:
app.post('/api/reviews', async (req, res) => {
const sessionId = req.headers['x-botsigged-id'];
const { productId, rating, comment } = req.body;
const session = await fetch(
`${BOTSIGGED_API}/sessions/${sessionId}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
).then(r => r.json());
// Determine moderation status based on score
let status;
if (session.bot_score < 30 && session.classification === 'human') {
status = 'published'; // Auto-approve trusted users
} else if (session.bot_score < 60) {
status = 'pending'; // Manual review
} else {
status = 'spam'; // Auto-reject
}
const review = await createReview({
productId,
rating,
comment,
status,
sessionId,
botScore: session.bot_score,
});
// Show success regardless of status
return res.json({ success: true });
});
Language-Specific Examples
Python
import httpx
class BotSigged:
def __init__(self, api_key: str, base_url: str):
self.api_key = api_key
self.base_url = base_url
self.client = httpx.Client(
headers={"Authorization": f"Bearer {api_key}"}
)
def get_session(self, session_id: str) -> dict:
response = self.client.get(f"{self.base_url}/sessions/{session_id}")
response.raise_for_status()
return response.json()
def validate(self, session_id: str, threshold: int = 50) -> dict:
response = self.client.post(
f"{self.base_url}/sessions/{session_id}/validate",
params={"threshold": threshold}
)
response.raise_for_status()
return response.json()
# Usage
botsigged = BotSigged(api_key="your-key", base_url="https://...")
@app.post("/signup")
async def signup(request: Request):
session_id = request.headers.get("x-botsigged-id")
validation = botsigged.validate(session_id, threshold=40)
if not validation["allow"]:
raise HTTPException(status_code=403, detail="Unable to create account")
# Create account...
Ruby
class BotSigged
def initialize(api_key:, base_url:)
@api_key = api_key
@base_url = base_url
end
def get_session(session_id)
response = Faraday.get("#{@base_url}/sessions/#{session_id}") do |req|
req.headers['Authorization'] = "Bearer #{@api_key}"
end
JSON.parse(response.body)
end
def validate(session_id, threshold: 50)
response = Faraday.post("#{@base_url}/sessions/#{session_id}/validate?threshold=#{threshold}") do |req|
req.headers['Authorization'] = "Bearer #{@api_key}"
end
JSON.parse(response.body)
end
end
# Usage
botsigged = BotSigged.new(api_key: 'your-key', base_url: 'https://...')
class SignupsController < ApplicationController
def create
session_id = request.headers['X-BotSigged-ID']
validation = botsigged.validate(session_id, threshold: 40)
unless validation['allow']
render json: { error: 'Unable to create account' }, status: :forbidden
return
end
# Create account...
end
end
Go
package botsigged
import (
"encoding/json"
"fmt"
"net/http"
)
type Client struct {
APIKey string
BaseURL string
HTTP *http.Client
}
type Session struct {
SessionID string `json:"session_id"`
BotScore int `json:"bot_score"`
Classification string `json:"classification"`
IsBot bool `json:"is_bot"`
Recommendation string `json:"recommendation"`
TriggeredFlags []string `json:"triggered_flags"`
}
type Validation struct {
SessionID string `json:"session_id"`
Allow bool `json:"allow"`
Reason string `json:"reason"`
BotScore int `json:"bot_score"`
Threshold int `json:"threshold"`
}
func (c *Client) GetSession(sessionID string) (*Session, error) {
req, _ := http.NewRequest("GET", fmt.Sprintf("%s/sessions/%s", c.BaseURL, sessionID), nil)
req.Header.Set("Authorization", "Bearer "+c.APIKey)
resp, err := c.HTTP.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var session Session
json.NewDecoder(resp.Body).Decode(&session)
return &session, nil
}
func (c *Client) Validate(sessionID string, threshold int) (*Validation, error) {
url := fmt.Sprintf("%s/sessions/%s/validate?threshold=%d", c.BaseURL, sessionID, threshold)
req, _ := http.NewRequest("POST", url, nil)
req.Header.Set("Authorization", "Bearer "+c.APIKey)
resp, err := c.HTTP.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var validation Validation
json.NewDecoder(resp.Body).Decode(&validation)
return &validation, nil
}
PHP
<?php
class BotSigged {
private string $apiKey;
private string $baseUrl;
public function __construct(string $apiKey, string $baseUrl) {
$this->apiKey = $apiKey;
$this->baseUrl = $baseUrl;
}
public function getSession(string $sessionId): array {
$ch = curl_init("{$this->baseUrl}/sessions/{$sessionId}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$this->apiKey}"
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
public function validate(string $sessionId, int $threshold = 50): array {
$ch = curl_init("{$this->baseUrl}/sessions/{$sessionId}/validate?threshold={$threshold}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$this->apiKey}"
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
// Usage
$botsigged = new BotSigged('your-key', 'https://...');
$validation = $botsigged->validate($_SERVER['HTTP_X_BOTSIGGED_ID'], 40);
if (!$validation['allow']) {
http_response_code(403);
echo json_encode(['error' => 'Unable to create account']);
exit;
}
// Create account...
Error Handling
Session Not Found
{
"error": "not_found",
"message": "Session not found"
}
This occurs when:
- The session ID is invalid
- The session belongs to a different site
- The session has expired (sessions expire after inactivity)
Recommended handling: Allow the request but log for investigation, or prompt the user to refresh the page.
API Errors
Always implement graceful degradation:
async function checkSession(sessionId) {
try {
const session = await botsigged.getSession(sessionId);
return { success: true, session };
} catch (error) {
// Log error for monitoring
console.error('BotSigged API error:', error);
// Fail open - allow request but flag for review
return {
success: false,
fallback: true,
error: error.message,
};
}
}
// Usage
const result = await checkSession(sessionId);
if (result.fallback) {
// API unavailable - allow but flag
await flagForManualReview(requestData);
}
Rate Limits
The API enforces rate limits per API key:
| Endpoint | Limit |
|---|---|
| GET /sessions/:id | 1000/minute |
| POST /sessions/:id/validate | 1000/minute |
Rate limit headers are included in responses:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1704067200
Best Practices
Cache Responses
For high-traffic endpoints, cache session data briefly:
const sessionCache = new Map();
async function getSession(sessionId) {
const cached = sessionCache.get(sessionId);
if (cached && Date.now() - cached.timestamp < 5000) {
return cached.data;
}
const session = await botsigged.getSession(sessionId);
sessionCache.set(sessionId, { data: session, timestamp: Date.now() });
return session;
}
Use Appropriate Thresholds
| Use Case | Recommended Threshold | Rationale |
|---|---|---|
| Account registration | 40 | Prevent fake accounts |
| Login | 60 | Balance security with UX |
| Purchase/checkout | 50 | Moderate fraud prevention |
| Comments/reviews | 40 | Reduce spam |
| Password reset | 50 | Protect sensitive action |
| Contact forms | 60 | Allow legitimate inquiries |
Log Everything
Log bot scores for security analysis and threshold tuning:
await analyticsLog.create({
event: 'form_submission',
sessionId,
botScore: session.bot_score,
classification: session.classification,
allowed: validation.allow,
reason: validation.reason,
endpoint: '/api/signup',
timestamp: new Date(),
});
Next Steps
- Server-Side Integration - SDK configuration for passing session IDs
- Classifications - Understanding session classifications
- Response Modes - Client-side automatic actions