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.
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.
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.