All API routes return JSON unless a route explicitly redirects for OIDC login/callback. Routes are served below /api, or below ${BASE_PATH}/api when BASE_PATH is configured. GET /api/health is always registered at the root path; when BASE_PATH is set, ${BASE_PATH}/api/health is registered too.
The browser UI authenticates with the HTTP-only crowdsec_web_ui_session cookie. There is no bearer-token API in this codebase. Authentication is enabled for new installs by default; migrated databases from older unauthenticated versions stay disabled until AUTH_ENABLED=true is set. When auth is enabled, protected API routes return 401 without a valid session.
Protected application routes also ensure the backend can authenticate to CrowdSec LAPI. If LAPI login fails, they return 502.
PERMISSION_READ_ONLY=true or a read-only user role blocks enforcement and management writes. Blocked requests return:
{ "error": "Read-only mode is enabled", "code": "READ_ONLY" }Read-only mode still allows user preferences and notification read-state writes.
List endpoints that support pagination use page and page_size. Pagination is enabled only when the page query parameter is present.
pagedefaults to1and is clamped to at least1.page_sizedefaults to50and is clamped from10to200.- Paginated responses use:
{
"data": [],
"pagination": {
"page": 1,
"page_size": 50,
"total": 0,
"total_pages": 0,
"unfiltered_total": 0
},
"selectable_ids": []
}GET /api/alerts and GET /api/decisions support a structured q search when paginated. Search supports free text, quoted phrases, AND, OR, NOT, -, grouping, field matching with :, exact matching with =, inequality with <>, and date comparisons with <, <=, >, >=.
Alert search fields: id, scenario, message, ip/source, country, as, target, date/created/created_at/time, sim/simulation, machine, origin.
Decision search fields: id, alert/alert_id, scenario/reason, ip/value, country, as, target, date/created/created_at/time, action, type, status, duplicate, sim/simulation, machine, origin.
Date range filters use dateStart and dateEnd. Use YYYY-MM-DD for day buckets or values containing T for hour-level comparisons. tz_offset is an offset in minutes used for local bucket comparisons when the server has no fixed TZ configured.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health |
Public health check returning { "status": "ok" }. |
These routes are mounted below /api/auth. Auth setup/login routes are available without a session so onboarding and login can work.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/auth/status |
Auth state, setup status, current user/session state, OIDC availability, passkey availability, and password-login state. |
| POST | /api/auth/setup |
Create the first admin user and start a session. Requires username and password; only works before any auth user exists. |
| POST | /api/auth/login |
Password login with username and password. |
| POST | /api/auth/logout |
Clear the session cookie. |
| GET | /api/auth/me |
Current authenticated session user. |
| GET | /api/auth/settings |
Auth settings visible to the current user, including OIDC settings metadata and password/passkey state. |
| PUT | /api/auth/settings |
Admin-only auth settings update. Can disable password login and configure OIDC issuer, client ID, client secret, scopes, groups claim, admin groups, read-only groups, and unmatched-user policy. |
| POST | /api/auth/change-password |
Change the current user's password. The user must be logged in with password auth. |
| GET | /api/auth/passkeys |
List passkeys for the current user. |
| PATCH | /api/auth/passkeys/:id |
Rename a passkey with { "name": "..." }. |
| DELETE | /api/auth/passkeys/:id |
Delete one of the current user's passkeys. |
| POST | /api/auth/webauthn/register/options |
Start passkey registration for the current user. |
| POST | /api/auth/webauthn/register/verify |
Complete passkey registration. Optional name is stored as the passkey label. |
| POST | /api/auth/webauthn/login/options |
Start passkey login. Optional username narrows allowed credentials. |
| POST | /api/auth/webauthn/login/verify |
Complete passkey login and start a session. |
| GET | /api/auth/oidc/login |
Redirect to the configured OIDC provider. |
| GET | /api/auth/oidc/callback |
OIDC callback handler; creates or updates the OIDC user session and redirects to the UI. |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/config |
Runtime UI config, LAPI status, sync status, simulation setting, time settings, metrics availability, metrics sidebar preference, and permissions. |
| PUT | /api/config/metrics-sidebar |
Save the metrics sidebar preference. Body: { "visible": true }. |
| PUT | /api/config/refresh-interval |
Update the refresh interval. Body: { "interval": "manual" | "0" | "5s" | "30s" | "1m" | "5m" }. Blocked in read-only mode. |
| PUT | /api/config/language |
Save language preference. Body: { "language": "browser" } or a supported locale code. |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/alerts |
List synced alerts. Without page, returns an array. With page, returns a paginated response. |
| GET | /api/alerts/:id |
Fetch alert details from CrowdSec LAPI, hydrate with decisions, and apply simulation visibility. :id must be numeric. |
| POST | /api/alerts/bulk-delete |
Delete multiple alerts by numeric ID. Body: { "ids": [1, "2"] }. Also deletes cached linked decisions. Blocked in read-only mode. |
| DELETE | /api/alerts/:id |
Delete one alert from CrowdSec LAPI and local cache. :id must be numeric. Blocked in read-only mode. |
Supported paginated alert filters: q, ip, country, scenario, as, date, dateStart, dateEnd, target, simulation, tz_offset.
simulation accepts all, live, or simulated; unknown values behave like all.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/decisions |
List decisions. Without page, returns an array. With page, returns a paginated response. Active decisions are returned by default. |
| POST | /api/decisions |
Add a manual CrowdSec decision through LAPI. Body: { "ip": "1.2.3.4", "duration": "4h", "reason": "manual", "type": "ban" }. type defaults to ban and accepts ban or captcha. Blocked in read-only mode. |
| POST | /api/decisions/bulk-delete |
Delete multiple decisions by numeric ID. Body: { "ids": [10, "11"] }. Blocked in read-only mode. |
| DELETE | /api/decisions/:id |
Delete one decision from CrowdSec LAPI and local cache. :id must be numeric. Blocked in read-only mode. |
Supported decision query parameters: include_expired, page, page_size, q, alert_id, country, scenario, as, ip, target, dateStart, dateEnd, simulation, hide_duplicates, tz_offset.
include_expired=trueincludes expired decisions within the configured lookback window.- Duplicate decisions are hidden by default in paginated results. Set
hide_duplicates=falseor filter byalert_idto show them. simulationacceptsall,live, orsimulated; unknown values behave likeall.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/cleanup/by-ip |
Delete cached/LAPI alerts and decisions for one IP address or range. Body: { "ip": "1.2.3.4" }. Blocked in read-only mode. |
| POST | /api/cache/clear |
Clear synced alert/decision data and run a bootstrap sync. Blocked in read-only mode. |
Bulk delete and cleanup responses use:
{
"requested_alerts": 0,
"requested_decisions": 0,
"deleted_alerts": 0,
"deleted_decisions": 0,
"failed": [],
"ip": "1.2.3.4"
}ip is only included for cleanup-by-IP responses.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/stats/alerts |
Alert records shaped for chart/stat consumers within the configured lookback window. |
| GET | /api/stats/decisions |
Decision records shaped for chart/stat consumers within the configured lookback window. |
| GET | /api/dashboard/stats |
Aggregated dashboard totals, filtered totals, top targets/countries/scenarios/AS, world-map country data, and history series. |
Supported dashboard filters: country, scenario, as, ip, target, dateStart, dateEnd, simulation, granularity, tz_offset.
simulationacceptsall,live, orsimulated.granularity=hourreturns hourly buckets; any other value uses daily buckets.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/metrics/crowdsec |
Fetch and normalize CrowdSec Prometheus metrics. Returns 404 when CROWDSEC_PROMETHEUS_URL is not configured and 502 when the metrics fetch fails. |
The response includes fetched_at, totals, bouncers, machines, parserSources, parserNodes, whitelists, and parserTimings. It can also include runtime-only observability sections: lapiRoutes and appsecEngines.
Parser node entries include isChild, which is true for CrowdSec child parser nodes emitted with the child- prefix.
Parser, LAPI latency, AppSec, bouncer, and machine values are derived from the current CrowdSec Prometheus scrape. The endpoint does not query Prometheus history or calculate Grafana-style rate()/increase() windows, so metrics that require time-window tracking are intentionally omitted.
Notification inbox routes operate on generated notification items.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/notifications |
List notification items. Supports page and page_size; defaults to page 1, size 50 when omitted. |
| POST | /api/notifications/:id/read |
Mark one notification as read. Allowed in read-only mode. |
| POST | /api/notifications/bulk-read |
Mark multiple notifications as read. Body: { "ids": ["id-1", "id-2"] }. Allowed in read-only mode. |
| POST | /api/notifications/bulk-delete |
Delete multiple notifications. Body: { "ids": ["id-1", "id-2"] }. Blocked in read-only mode. |
| POST | /api/notifications/delete-read |
Delete all read notifications. Blocked in read-only mode. |
| DELETE | /api/notifications/:id |
Delete one notification. Blocked in read-only mode. |
| GET | /api/notifications/settings |
List notification channels and rules. |
Notification configuration routes manage destinations and rule definitions.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/notification-channels |
Create a notification channel. Blocked in read-only mode. |
| PUT | /api/notification-channels/:id |
Update a notification channel. Blocked in read-only mode. |
| DELETE | /api/notification-channels/:id |
Delete a notification channel. Blocked in read-only mode. |
| POST | /api/notification-channels/:id/test |
Send a test notification through a saved channel. Blocked in read-only mode. |
| POST | /api/notification-rules |
Create a notification rule. Blocked in read-only mode. |
| PUT | /api/notification-rules/:id |
Update a notification rule. Blocked in read-only mode. |
| DELETE | /api/notification-rules/:id |
Delete a notification rule. Blocked in read-only mode. |
Channel create/update body:
{
"name": "Security alerts",
"type": "ntfy",
"enabled": true,
"config": {}
}Supported channel types: ntfy, gotify, email, mqtt, webhook.
Rule create/update body:
{
"name": "IP bans",
"type": "ip-ban",
"enabled": true,
"severity": "warning",
"channel_ids": ["channel-id"],
"config": {}
}Supported rule types: alert-spike, alert-threshold, new-alert-decision, new-cve, ip-ban, application-update, lapi-availability.
Supported severities: info, warning, critical.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/update-check |
Check whether a newer application release is available. Response is not cached. |
Optional query parameters override the runtime version metadata used for the check: version, branch, commit_hash.
List the first page of active decisions:
curl -b cookie.txt 'http://localhost:3000/api/decisions?page=1&page_size=50'Search alerts with structured syntax:
curl -b cookie.txt 'http://localhost:3000/api/alerts?page=1&page_size=50&q=origin:(manual%20OR%20CAPI)%20AND%20-country:us'Add a manual ban:
curl -b cookie.txt \
-H 'Content-Type: application/json' \
-d '{"ip":"1.2.3.4","duration":"4h","type":"ban","reason":"manual"}' \
http://localhost:3000/api/decisions