Get the attack mode state
GET /v1/attack-protection/attack-mode · permission attack-protection:read
Returns whether the environment is in attack mode, and the attack mode periods that started in the last 90 days or are still open, newest first (at most 100; more tells you that older ones exist in that window).
While the environment is in attack mode, every password and one-time code step asks for a harder bot challenge, whatever bot_protection.mode says. Passkey and social sign-in are not challenged. A period opens in one of three ways:
auto: failed sign-ins in a 5-minute window passed the trigger threshold (the larger of 50 and ten times the environment's median). Inlogmode ofcredential_stuffingthe period is recorded withwould_have: trueand nothing is enforced, unless the window passes three times the threshold.manual_customer: you turned it on withactivate.manual_platform: KeenAuth operations turned it on.
active is true only while an enforced period (would_have: false) covers the whole environment; active_until is then the latest end of those periods. A period whose end has passed but that the cleanup has not closed yet reads as ended at ends_at. Who opened a manual period is in the management audit log, not in this response.
Response
200 OK
| Field | Type | Description |
|---|---|---|
active |
boolean | The environment is in attack mode now. |
active_until |
string (date-time) or null | When the current attack mode ends, unless an automatic period is extended; null when active is false. |
periods[] |
array | Periods, newest first. |
periods[].id |
string | Period id, prefixed atm_. |
periods[].scope |
string | environment or org_domain. |
periods[].org_domain |
string or null | The organization email domain of an org_domain period. |
periods[].trigger |
string | auto, manual_customer or manual_platform. |
periods[].would_have |
boolean | true: recorded in log mode, not enforced. |
periods[].trigger_value |
integer or null | Failed attempts in the 5-minute window that opened an auto period; null for manual periods. |
periods[].threshold |
integer or null | The threshold that window passed; null for manual periods. |
periods[].started_at |
string (date-time) | When the period started. |
periods[].ends_at |
string (date-time) | When the period ends by itself. An auto period is extended while the attack goes on. |
periods[].ended_at |
string (date-time) or null | When the period ended; null while it is open. |
more |
boolean | Older periods exist in the last 90 days. |
{
"active": true,
"active_until": "2026-10-20T10:00:00Z",
"periods": [
{
"id": "atm_01jaz8m5c3f6t9w2y4b7d0g3k6",
"scope": "environment",
"org_domain": null,
"trigger": "manual_customer",
"would_have": false,
"trigger_value": null,
"threshold": null,
"started_at": "2026-10-20T09:00:00Z",
"ends_at": "2026-10-20T10:00:00Z",
"ended_at": null
}
],
"more": false
}
Errors
Every error is an application/problem+json body with a stable code.
| HTTP | code |
When |
|---|---|---|
| 401 | unauthenticated |
The API key is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The key lacks the attack-protection:read permission. |
| 429 | rate_limited |
The rate limit was exceeded; honor Retry-After. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry later. |
Example
curl https://api.eu.keenauth.com/v1/attack-protection/attack-mode \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
CLI: keenauth attack-protection attack-mode get