API Introduction
The Seclai REST API allows you to programmatically create and manage AI agents, knowledge bases, sources, solutions, runs, alerts, and AI-assisted configuration. This page provides an overview of how to get started with the API.
Base URL
All API requests should be made to:
https://api.seclai.com/
Authentication
The Seclai API supports two authentication methods: OAuth (recommended) and API keys.
OAuth Authentication (Recommended)
OAuth uses your Seclai account credentials via Cognito. Include a Bearer token in the Authorization header:
Authorization: Bearer YOUR_ACCESS_TOKEN
OAuth tokens are obtained through the standard OAuth 2.0 Authorization Code flow with PKCE. MCP clients handle this automatically — just enter the server URL and sign in when prompted.
To target a different organization's account, include the X-Account-Id header:
Authorization: Bearer YOUR_ACCESS_TOKEN
X-Account-Id: ORGANIZATION_ACCOUNT_ID
API Key Authentication
API keys are best suited for server-to-server integrations. Include your API key in the X-API-Key header:
X-API-Key: YOUR_API_KEY
Get Your API Key
- Log in to your Seclai account
- Navigate to API Keys in the left sidebar
- Click "Create API Key"
- Copy your key and store it securely right away. The key will not be shown again.
Important: Treat your API keys like passwords. Never share them or commit them to version control. Each user should create their own key.
Calling from a Browser
You can't. The API sends no CORS headers, and neither credential type can be narrowed for a browser: there are no per-resource or read-only scopes, so a leaked key or token carries every permission its identity holds. Browser-facing apps call their own backend, which calls Seclai. See Calling from a Browser for the reasoning and the proxy checklist.
Making Requests
Example Request
curl https://api.seclai.com/agents \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json"
Request Headers
| Header | Required | Description |
|---|---|---|
Authorization | * | OAuth Bearer token: Bearer YOUR_ACCESS_TOKEN |
X-API-Key | * | Your API key (alternative to OAuth) |
X-Account-Id | No | Target a different organization account (OAuth only) |
Seclai-Version | No | Opt into dated API changes — see API Versioning |
Content-Type | Yes | Set to application/json for POST/PUT requests |
* One of Authorization or X-API-Key is required.
Response Format
All responses are returned as JSON. Successful responses will have a 200 status code and include the requested data:
{
"id": "agent_abc123",
"name": "My Agent",
"status": "active",
"created_at": "2026-01-12T10:00:00Z"
}
Error Responses
Error responses carry an error object with a machine-readable code and a human-readable message (plus occasional extra fields, e.g. retry_after, callers):
{
"error": {
"code": "agent_in_use",
"message": "This agent is still called by other live agents."
}
}
Request-validation failures (a missing or malformed body field, a bad query-parameter type, or an unknown query parameter) historically returned a different { "detail": [...] } envelope. On Seclai-Version: 2026-07-27 or later they are unified into the same error envelope, with the per-field breakdown under details:
{
"error": {
"code": "validation_error",
"message": "field required",
"details": [
{ "type": "missing", "loc": ["body", "name"], "msg": "field required" }
]
}
}
Clients on an older version keep the { "detail": [...] } shape for validation errors. One exception on every version: a malformed Seclai-Version header is rejected with { "detail": [...] } (it is rejected before a version can be resolved, so the response cannot be version-gated). Always branch on HTTP status first; then parse error (or, for validation errors on a legacy version, detail).
API Versioning
The API evolves without breaking existing integrations by making backward-incompatible changes opt-in through a dated version. The version a request runs under is resolved in this order:
-
Seclai-Versionrequest header (if present) — overrides everything for that one request, so you can test a new version on demand:curl https://api.seclai.com/agents \ -H "X-API-Key: YOUR_API_KEY" \ -H "Seclai-Version: 2026-07-27" -
Your account's pinned version — a sticky default for every request you make without the header. New accounts are pinned to the latest version at signup; accounts that predate a change stay on their existing version, so a release never changes behavior under you.
-
The baseline — if your account is unpinned, requests fall back to a stable legacy baseline.
Sending (or pinning) a date opts into every change released on or before it. Every response echoes the version it was served with in the Seclai-Version response header; a malformed value (not YYYY-MM-DD) returns 422. The published OpenAPI spec carries an x-seclai-versions object listing the default, latest, and all known versions.
Managing your account's version
GET /version reports your pinned version, the version the current request resolved to, and the known versions. An account owner or admin can pin (or clear) it with PUT /version:
# Pin the whole account to a version (applies to every future request)
curl -X PUT https://api.seclai.com/version \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"version": "2026-07-27"}'
# Clear the pin (revert to the baseline)
curl -X PUT https://api.seclai.com/version \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"version": null}'
Changes by version
| Version | What it changes |
|---|---|
2026-07-27 | Unknown query parameters are rejected with 422 instead of silently ignored. Every list endpoint returns the canonical { data, pagination } envelope (see Pagination) — previously some returned a bare array, a flat { data, total, page, limit }, a { configs, total }, or another per-resource key. Request-validation errors use the unified { error: { code, message, details } } envelope instead of { detail: [...] }. GET /agents/evaluation-results/non-manual-summary also gains an agent_id scoping parameter. |
2026-08-03 | Memory banks: the retired compaction threshold max_age_days is rejected with 400 and reads back as null — 0 stays accepted, since it is the sentinel that clears a value stored earlier. An omitted retention_days on create resolves per bank type — 90 days for a conversation bank, indefinite for a general bank — instead of a flat 30 days. An explicit retention_days (including null) is honoured on every version. See Memory Banks. |
2026-08-21 | POST /sources rejects a dimensions value the chosen embedding_model does not support, with 400 and the allowed values, instead of storing it. Such a source could never be indexed — every later ingest failed with "No embedding model for dimensions N", far from the request that caused it. GET /models/embedders reports the supported dimensions per embedder. Omitting dimensions still uses the default on every version. See Embedding Models. |
Authentication Error Codes
| HTTP Status | Error Code | Meaning |
|---|---|---|
| 401 | API_NOT_AUTHENTICATED | Missing or invalid API key / Bearer token |
| 401 | USER_NOT_AUTHENTICATED | OAuth Bearer token could not be verified |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests — see Retry-After header |
Pagination
Every list endpoint returns the same envelope: the items under data, and a
pagination object. Paginate with page/limit (or limit/offset, depending
on the endpoint):
curl "https://api.seclai.com/agents?page=1&limit=20" \
-H "X-API-Key: YOUR_API_KEY"
Response (on Seclai-Version: 2026-07-27 or later):
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"pages": 8,
"has_next": true,
"has_prev": false
}
}
Because the shape is uniform, one helper can unwrap data and read
pagination.has_next for any list endpoint. Naturally-bounded lists
(reference data, relationship lists) return the whole set as a single page
(has_next: false). The search endpoints (/search, /docs-search) are the
exception — they return ranked results as { "results": [...] } (not a paginated
collection). Clients on an older version keep each endpoint's legacy shape until
they opt in.
SDKs
We provide official SDKs to make integration easier:
- Python SDK -
pip install seclai - JavaScript SDK -
npm install @seclai/sdk - Go SDK -
go get github.com/seclai/seclai-go - C# SDK -
dotnet add package Seclai - CLI Tool -
npm install -g @seclai/cli— includes built-in skills for common workflows
Rate Limits
The API enforces rate limits to protect service quality. Limits apply at two levels:
Global Limits
All API requests are subject to a per-IP limit of 120 requests per minute and a per-account limit of 300 requests per minute, regardless of plan.
Plan-Specific Limits
Your plan defines the maximum API requests allowed per minute. When you exceed this limit, the API returns a 429 Too Many Requests response.
Rate Limit Headers
Every successful API response includes rate-limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the rate limit window resets |
429 Too Many Requests
When rate-limited, the response includes a Retry-After header and a structured error body:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "API request quota exceeded: 60/60 requests per minute. Retry after 45s.",
"retry_after": 45
}
}
Best practices:
- Check
X-RateLimit-Remainingto anticipate limits before hitting them. - On a
429response, wait for theRetry-Afterduration before retrying. - Use exponential backoff for transient failures.
Webhooks
Configure webhooks to receive real-time notifications about events in your account:
{
"event": "agent.run.completed",
"data": {
"run_id": "run_xyz789",
"agent_id": "agent_abc123",
"status": "completed"
}
}
Set up webhooks in your account settings.
Next Steps
- API Reference - Complete endpoint documentation
- API Examples - Common use cases and code samples
- Model Lifecycle API Examples - Auto-upgrade and rollback settings for agents and steps
- Authentication Guide - Detailed authentication setup