Base URL & Authentication
Base URL: https://api.execlave.com# All endpoints below are versioned under /api/v1 # Two authentication methods: # 1. API Key (recommended for SDK/automation)curl -H "X-API-Key: exe_prod_your_key_here" ... # 2. Logto JWT (used by the dashboard)curl -H "Authorization: Bearer <logto_jwt>" ...All endpoints require authentication. API Keys are prefixed with exe_prod_ (production), exe_stg_ (staging), or exe_dev_ (development). Generate keys from Settings → API Keys.
Machine-readable spec. The full OpenAPI document is served live at api-docs.json , with a browsable UI at /api-docs. Point a client generator at the JSON to produce a typed SDK for any language.
Response format
Success (single item)
{ "data": { "id": "uuid", ... } }Success (list)
{ "data": [...], "meta": { "total": 42 } }Error
{ "error": { "code": "VALIDATION_ERROR", "message": "...", "fields": { ... } } }Agents
Traces
Policies
Access Grants
Webhooks
Verifying webhook signatures
Every outbound delivery is signed with HMAC-SHA256 using your webhook's signing secret. The current scheme (v2) binds a timestamp into the signed string to prevent replay attacks; the legacy v1 scheme remains supported for in-flight deliveries during a deploy.
| Header | Description |
|---|---|
X-Execlave-Signature | sha256=<hex> — HMAC of the signed payload. |
X-Execlave-Signature-Version | v1 or v2. Default when the header is absent: v1. |
X-Execlave-Timestamp | Unix-seconds timestamp from when the delivery was signed. Sent on v2 only. Receivers should reject deliveries outside a ±5-minute window. |
X-Execlave-Idempotency-Key | Stable per logical event (deterministic in org/event/body) — same value across retries. Use this to dedupe on the receiver. |
Receiver-side verification (Node.js):
const crypto = require('crypto'); function verify(headers, rawBody, secret) { const ts = headers['x-execlave-timestamp']; const sig = headers['x-execlave-signature'].replace('sha256=', ''); const ver = headers['x-execlave-signature-version'] ?? 'v1'; const signedPayload = ver === 'v2' ? `${ts}.${rawBody}` : rawBody; const expected = crypto.createHmac('sha256', secret) .update(signedPayload) .digest('hex'); // Constant-time comparison const a = Buffer.from(expected, 'hex'); const b = Buffer.from(sig, 'hex'); if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) { throw new Error('Invalid webhook signature'); } // v2: enforce a sliding replay window (±5 minutes recommended) if (ver === 'v2') { const now = Math.floor(Date.now() / 1000); if (Math.abs(now - parseInt(ts, 10)) > 300) { throw new Error('Webhook timestamp outside replay window'); } }} // Idempotency: dedupe on X-Execlave-Idempotency-Key (stable across retries).// Persist the key with a short TTL (e.g. 24h) and reject duplicates.Important: verify against the raw request bytes, not a re-serialized JSON object — any whitespace or key-order change will break the HMAC comparison.
Incidents
Status transitions & side effects
Moving an incident to resolved, closed, or false_positive stamps the resolution timestamps used to compute time_to_resolution_seconds, appends a status_change entry to the timeline, and notifies the assignee. Creating an incident with an agentId also dispatches a trace.error webhook event. Every create and update is written to the tamper-evident audit log.
Alerts
Rule lifecycle & triage endpoints
| Endpoint | Role | What it does |
|---|---|---|
GET /alerts/rules/:id | viewer | Fetch a single rule. |
PATCH /alerts/rules/:id/toggle | developer | Enable or disable a rule without a full update — the usual way to silence a noisy rule. |
DELETE /alerts/rules/:id | admin | Delete a rule. Fired history is retained. |
POST /alerts/fire | developer | Fire an alert manually — useful for testing notification routing end to end. |
PATCH /alerts/history/:id/acknowledge | developer | Mark a firing alert as acknowledged; stamps acknowledgedAt / acknowledgedBy. |
PATCH /alerts/history/:id/resolve | developer | Resolve the alert and stamp resolvedAt. |
PATCH /alerts/history/:id/snooze | developer | Suppress re-notification until snoozedUntil passes. |
Anomaly Detection & Forecasting
Requires the processing service
These endpoints are served by the Python processing service. Check GET /api/v1/anomaly/health first — it reports available, measured latencyMs, database connectivity, and a reason when degraded. When the service is unavailable, the detection, RCA, and forecast endpoints cannot produce results.
Remaining anomaly endpoints
| Endpoint | Role | What it does |
|---|---|---|
GET /anomaly/configs | viewer | List detection configs. GET /configs/:id fetches one; DELETE /configs/:id (admin) removes it. |
GET /anomaly/events | viewer | List detected anomaly events. |
PATCH /anomaly/events/:id/acknowledge | developer | Acknowledge an anomaly event. |
GET /anomaly/baselines | viewer | Inspect the learned per-metric baselines detection scores against. |
POST /anomaly/baselines/rebuild | admin | Rebuild baselines. Body: agentId (optional), metrics[] (defaults to all three), lookbackHours (1–720, default 168). |
POST /anomaly/rca | developer | Run root-cause analysis for an incident. Body: incidentId (required UUID), windowHours (1–48, default 4). |
GET /anomaly/rca/:incidentId | viewer | Fetch a previously computed RCA result. |
GET /anomaly/forecast/history | viewer | List past forecast runs. |
Rate limits
| Route group | Limit | Window |
|---|---|---|
| Control plane (agents, policies, etc.) | 100 requests | per minute |
| Trace ingestion (POST /traces/ingest) | 1,000 requests | per minute |
| Policy enforcement (POST /policies/enforce) | 10,000 requests | per minute |
Limits are per organization. The enforcement bucket is sized for SDK hot-path traffic and can be tuned per deployment via ENFORCEMENT_RATE_LIMIT_PER_MINUTE. When rate limited, the API returns 429 Too Many Requests with a Retry-After header. The frontend API client and SDKs handle retries automatically with exponential backoff.