Skip to main content

Overview & Authentication

All endpoints are served from the backend at /api/*.

Authentication

Web Endpoints (Clerk JWT)

Most endpoints require a Clerk JWT in the Authorization header:

curl -H 'Authorization: Bearer <clerk-jwt>' https://backend.example.com/api/browser/tests

Agent Device Endpoints

Agent endpoints use an API key issued during enrollment:

curl -H 'X-Agent-Key: <api-key>' -H 'X-Agent-ID: <agent-id>' https://backend.example.com/api/agent/heartbeat

Response Format

Success

{ "success": true, "data": { ... } }

Error

{ "success": false, "error": "Error message" }

Rate Limits

Endpoint GroupLimit
Enrollment5 / 15 min per IP
Device (heartbeat, tasks)100 / 15 min per agent
Binary download10 / 15 min per IP
Key rotation3 / 15 min per IP
Auth20 / 15 min per IP

Route Groups

PrefixAuthPurpose
/api/browser/*ClerkTest browser
/api/analytics/*ClerkElasticsearch analytics
/api/analytics/defender/*ClerkDefender analytics
/api/agent/admin/*ClerkAgent management
/api/agent/*Agent keyDevice endpoints
/api/tests/*ClerkBuild system, certificates
/api/integrations/*ClerkDefender, alerting config
/api/analytics/risk-acceptances/*ClerkRisk acceptance management
/api/users/*ClerkUser management, invitations
/api/auth/*None/ClerkCLI device flow auth

Route Architecture

The API is organized into domain-specific route modules, each backed by dedicated services:

Cross-Module Integration Patterns

The route modules are not isolated — several critical workflows span multiple modules:

Test Execution Pipeline

Browser Routes → Tests Routes → Agent Routes → Analytics Routes → Alerting
  1. Browse: User discovers tests via Browser Routes
  2. Build: Tests Routes compile and sign the binary
  3. Dispatch: Agent admin routes create tasks for target agents
  4. Execute: Agent device routes receive tasks and report results
  5. Analyze: Analytics Routes query Elasticsearch for defense metrics
  6. Alert: If thresholds are breached, Integration Routes trigger notifications

Agent Lifecycle

Enrollment → Heartbeat → Task Polling → Result Ingestion → Key Rotation

All managed through Agent Routes with different auth strategies per sub-route:

  • Public: Enrollment and binary downloads (rate-limited, no auth)
  • Agent-authenticated: Heartbeat, task fetch, result submission (API key)
  • Admin: Fleet management, task creation, scheduling (Clerk JWT)

Configuration Flow

Integration Routes → Defender Routes → Analytics Routes

Defender credentials saved via Integration Routes enable the Defender sync service, which populates data queried by Defender Analytics Routes.

Security Architecture

Authentication Tiers

TierMechanismEndpointsKey Generator
PublicRate limiting onlyAgent downloads, enrollmentIP address
Agent deviceX-Agent-Key + X-Agent-ID headersHeartbeat, tasks, resultsAgent ID
Clerk JWTAuthorization: Bearer <jwt>All admin endpointsUser ID
Cron secretCRON_SECRET header (Vercel only)Scheduled jobsN/A

Input Validation

All routes validate inputs before passing to services:

  • UUID format checks prevent path traversal in ID parameters
  • Platform validation (os must be windows, linux, or darwin)
  • Payload size limits protect against oversized uploads
  • Type coercion via extractFilterParams() normalizes query string types

Response Format Details

Standard Success

{
"success": true,
"data": { ... }
}

Paginated Lists

{
"success": true,
"data": [ ... ],
"total": 142,
"page": 1,
"pageSize": 50
}

Error Responses

{
"success": false,
"error": "Human-readable error message"
}

HTTP status codes follow standard conventions: 400 for validation errors, 401 for authentication failures, 403 for authorization failures, 404 for missing resources, 429 for rate limits, and 500 for server errors.

Error Handling Pattern

All async route handlers are wrapped with asyncHandler(), which catches rejected promises and forwards them to the global error middleware. Throw AppError with an HTTP status code for structured error responses:

throw new AppError('Resource not found', 404);