·4 min read

Webhook Events and Alert Logic: A Technical Reference for Integrators

A complete reference for EdTech developers integrating ProctorSafe — covering every webhook event type, payload schema, signature verification, and alert escalation logic.

Overview

ProctorSafe's integration model is designed for developers who need programmatic access to proctoring session data — whether that's routing alerts to a student information system, building custom dashboards, or automating post-exam workflows.

All session data is delivered via webhook — outbound HTTPS POST requests to your endpoint. ProctorSafe does not offer a pull-based REST API for session data; this ensures that no data is held in memory longer than necessary and that delivery is guaranteed even if your system is temporarily unavailable.


Webhook endpoint requirements

Your endpoint must:

  • Accept POST requests with Content-Type: application/json
  • Respond with HTTP 200 within 5 seconds to acknowledge receipt
  • Be reachable over HTTPS (HTTP endpoints are rejected)
  • Be reachable from ProctorSafe's outbound IPs (whitelist provided on request)

ProctorSafe retries failed deliveries using exponential backoff: 3 attempts at 30s, 5m, and 30m intervals. After 3 failures, the event is marked as undelivered and can be re-requested via the Events Replay API for up to 72 hours.


Event types

session.started

Fired when a student begins a proctored exam.

{
  "event": "session.started",
  "timestamp": 1718000000,
  "exam_id": "EX-2024-0412",
  "session_id": "sess_8f3k2m",
  "institution_id": "inst_mougins",
  "student_identifier": null,
  "metadata": {
    "browser_ua": "Mozilla/5.0...",
    "screen_resolution": "1920x1080",
    "timezone": "Europe/Paris",
    "sdk_version": "1.4.2"
  }
}

Note: student_identifier is null unless your integration passes it via LTI launch. If you rely on LMS roster sync, the identifier is resolved asynchronously within 5 minutes.


proctoring_event.tab_switch

Fired when the student switches away from the exam tab.

{
  "event": "proctoring_event.tab_switch",
  "timestamp": 1718000120,
  "session_id": "sess_8f3k2m",
  "duration_ms": 3200,
  "count_this_session": 3
}

Important: tab_switch events include a duration_ms field. A 3-second switch to check a reference document is a legitimate use case. Whether to flag it is a policy decision on your side — ProctorSafe does not enforce a threshold here, it just delivers the signal.


proctoring_event.face_absent

Fired when the SDK detects no face in the webcam frame for longer than the configured threshold (default: 5 seconds).

{
  "event": "proctoring_event.face_absent",
  "timestamp": 1718000450,
  "session_id": "sess_8f3k2m",
  "duration_ms": 8200,
  "confidence": 0.97
}

confidence is the SDK's assessment that no face is present (0.0–1.0). Values below 0.85 are typically caused by poor lighting and are worth reviewing before escalation.


proctoring_event.face_mismatch

Fired when the face detected during the exam does not match the face enrolled at session start.

{
  "event": "proctoring_event.face_mismatch",
  "timestamp": 1718000500,
  "session_id": "sess_8f3k2m",
  "confidence": 0.12,
  "re_enrolled": false
}

Security note: face_mismatch is a high-severity event by default. Your endpoint should treat it as requiring immediate review, not auto-dismissal.


proctoring_event.audio_anomaly

Fired when ambient audio exceeds the configured threshold (if audio monitoring is enabled).

{
  "event": "proctoring_event.audio_anomaly",
  "timestamp": 1718000600,
  "session_id": "sess_8f3k2m",
  "peak_db": 68,
  "duration_ms": 4500,
  "count_this_session": 1
}

Audio level is reported in dB. The default threshold is 65dB. Note that this event only fires if your institution has explicitly enabled audio monitoring in the ProctorSafe admin panel.


proctoring_event.devtools_open

Fired if the browser developer tools are opened during the session.

{
  "event": "proctoring_event.devtools_open",
  "timestamp": 1718000800,
  "session_id": "sess_8f3k2m"
}

session.ended

Fired when the student submits the exam or the session is terminated.

{
  "event": "session.ended",
  "timestamp": 1718010000,
  "session_id": "sess_8f3k2m",
  "exit_reason": "submitted",
  "total_duration_seconds": 3600,
  "events_summary": {
    "tab_switches": 4,
    "face_absences": 2,
    "face_mismatches": 0,
    "audio_anomalies": 0,
    "devtools_opens": 0
  },
  "risk_score": 0.3
}

risk_score is a composite score (0.0–1.0) computed by the ProctorSafe analysis engine. It is not a verdict — it's a signal for your reviewer. A score above 0.7 warrants closer review; above 0.9 should trigger an escalation workflow.


Signature verification

Every webhook delivery includes an X-ProctorSafe-Signature header for verification:

X-ProctorSafe-Signature: sha256=a1b2c3d4e5f6...

The signature is computed as:

HMAC-SHA256(timestamp + "." + raw_body, webhook_secret)

Where webhook_secret is the value assigned to your integration in the ProctorSafe developer portal.

Verification steps in your handler:

  1. Extract X-ProctorSafe-Timestamp — reject if older than 5 minutes (replay attack protection)
  2. Compute the expected signature
  3. Compare using a constant-time comparison function — never use == for HMAC comparison
import hmac
import hashlib
import time

def verify_signature(payload_body, timestamp_header, signature_header, secret):
    # Reject events older than 5 minutes
    if abs(time.time() - int(timestamp_header)) > 300:
        raise ValueError("Webhook timestamp too old")

    expected = hmac.new(
        secret.encode(),
        f"{timestamp_header}.{payload_body}".encode(),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected, signature_header):
        raise ValueError("Invalid webhook signature")

Alert escalation logic

ProctorSafe provides a default alert pipeline, but the escalation rules are configurable per institution. Here's how the default logic works:

Event captured (on-device)
  → Encrypted signal sent to ProctorSafe servers
  → Signal stored in session log (anonymous, no PII)
  → Alert evaluated against institution thresholds

  IF risk_score >= escalation_threshold:
    → Route to reviewer dashboard
    → Optionally fire webhook to your SIS (if configured)
    → Optional: send notification to instructor (email/in-app)

  IF risk_score >= critical_threshold:
    → Alert marked as HIGH priority
    → Optional: auto-pause exam session (configurable)
    → Optional: webhook to your SIS with flag: urgent: true

The escalation_threshold and critical_threshold are set in the ProctorSafe admin panel and are scoped per exam type.


Testing your integration

Use the ProctorSafe webhook testing tool in the developer portal to:

  1. Replay any historical event — replay a specific event type with a specific payload
  2. Send a test event — fire a custom payload to your endpoint without affecting live sessions
  3. View delivery logs — see retry attempts, HTTP status codes, and failure reasons

For local development, use a tool like ngrok or smee.io to expose a local endpoint.


Event Replay API

If your endpoint was unavailable and you missed events, use the Events Replay API:

GET /v1/events/replay?session_id={session_id}&from={timestamp}&to={timestamp}
Authorization: Bearer {api_key}

Returns all events for the specified session within the time window. Events are available for replay for 72 hours after session end.


SDK vs. webhook scope

A common integration question: where does the SDK end and the webhook begin?

WhatWhere
Face detectionOn-device SDK
Tab switching detectionOn-device SDK
Audio level monitoringOn-device SDK
Event signal encryption & deliveryProctorSafe servers
Alert log storageProctorSafe servers
Webhook delivery to your endpointProctorSafe servers
Dashboard, review workflow, SIS integrationYour systems

The SDK never talks directly to your systems — all data flows through ProctorSafe's server layer, which applies encryption, anonymisation, and access control before any event reaches your webhook endpoint.


EdTech developers: full API documentation, SDK reference, and sandbox credentials are available at proctorsafe.eu/docs. For integration support, contact the team with your institution ID and a description of your use case.