Reference

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