Stitchflow
Abnormal Security logo

Abnormal Security User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 17, 2026

Summary and recommendation

The Abnormal Security REST API is versioned at /v1/ and authenticates via a static Bearer token issued from the portal under Settings → Integrations → API Keys.

Token permissions are not scope-gated at the token level;

they inherit the portal role of the creating user, meaning tokens created by non-admin users may return HTTP 403 on certain endpoints.

The API is strictly read-only for account and user data - there are no write, update, or delete operations on user records.

Pagination is 1-based integer (pageNumber);

iterate until nextPageNumber is null in the response body.

Rate limits are enforced but thresholds and retry headers are not publicly documented;

implement exponential backoff on HTTP 429.

API quick reference

Has user APIYes
Auth methodBearer token (static API key issued from the Abnormal Security portal)
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredN/A

Authentication

Auth method: Bearer token (static API key issued from the Abnormal Security portal)

Setup steps

  1. Log in to the Abnormal Security portal (portal.abnormalsecurity.com).
  2. Navigate to Settings → Integrations → API Keys.
  3. Click 'Create API Key', assign a name and optional expiry, then copy the generated token.
  4. Include the token in every request as the HTTP header: 'Authorization: Bearer '.

Required scopes

Scope Description Required for
N/A Abnormal Security API tokens are not scope-gated at the token level; access is determined by the portal role of the user who created the token. All endpoints

User object / data model

Field Type Description On create On update Notes
email string Primary email address of the employee/account. N/A – read-only from Abnormal's detection data N/A Used as the unique identifier for account lookups.
name string Display name of the employee. N/A N/A Populated from the connected mail environment.
riskScore string Abnormal-computed risk score for the account (e.g., 'high', 'medium', 'low'). N/A N/A Reflects behavioral and threat signals.
riskLevel string Categorical risk level derived from riskScore. N/A N/A
compromisedSince string (ISO 8601) Timestamp when the account was first flagged as compromised. N/A N/A Null if account is not currently compromised.
isVip boolean Whether the account is marked as a VIP/executive. N/A N/A
department string Department of the employee as sourced from the mail environment. N/A N/A
title string Job title of the employee. N/A N/A
isActive boolean Whether the account is currently active in the mail environment. N/A N/A

Core endpoints

List accounts

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/accounts
  • Watch out for: Returns accounts Abnormal has observed; it is not a writable directory. pageNumber is 1-based.

Request example

GET /v1/accounts?pageNumber=1 HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "accounts": [
    {"email": "user@example.com", "name": "Jane Doe", "riskScore": "high"}
  ],
  "nextPageNumber": 2
}

Get account details

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/accounts/{email}
  • Watch out for: The email address must be URL-encoded in the path.

Request example

GET /v1/accounts/user%40example.com HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "email": "user@example.com",
  "name": "Jane Doe",
  "riskScore": "high",
  "isVip": false,
  "department": "Finance"
}

Get account-related cases

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/accounts/{email}/cases
  • Watch out for: Returns ATO (account takeover) cases linked to the account, not general threat messages.

Request example

GET /v1/accounts/user%40example.com/cases HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "cases": [
    {"caseId": "1234", "severity": "HIGH", "status": "Open"}
  ]
}

List threats (messages)

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/threats
  • Watch out for: Threats are message-level objects, not user objects. Filter by recipient to correlate with a specific user.

Request example

GET /v1/threats?pageNumber=1 HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "threats": [
    {"threatId": "abc123", "subject": "Invoice", "receivedTime": "2024-01-10T12:00:00Z"}
  ],
  "nextPageNumber": 2
}

Get threat details

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/threats/{threatId}

Request example

GET /v1/threats/abc123 HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "threatId": "abc123",
  "subject": "Invoice",
  "attackType": "BEC",
  "recipientAddress": "user@example.com"
}

List cases

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/cases
  • Watch out for: Cases represent ATO investigations; severity values are HIGH, MEDIUM, LOW.

Request example

GET /v1/cases?pageNumber=1 HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "cases": [
    {"caseId": "1234", "severity": "HIGH", "affectedEmployee": "user@example.com"}
  ],
  "nextPageNumber": null
}

Get case details

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/cases/{caseId}

Request example

GET /v1/cases/1234 HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "caseId": "1234",
  "severity": "HIGH",
  "status": "Open",
  "affectedEmployee": "user@example.com",
  "firstObserved": "2024-01-09T08:00:00Z"
}

Get vendor (third-party) details

  • Method: GET
  • URL: https://api.abnormalsecurity.com/v1/vendors/{vendorDomain}
  • Watch out for: Vendor endpoints are part of Vendor Email Compromise (VEC) detection; availability may depend on licensed modules.

Request example

GET /v1/vendors/supplier.com HTTP/1.1
Host: api.abnormalsecurity.com
Authorization: Bearer <token>

Response example

{
  "vendorDomain": "supplier.com",
  "riskScore": "medium",
  "engagementHistory": []
}

Rate limits, pagination, and events

  • Rate limits: Abnormal Security enforces rate limits but does not publicly document specific numeric thresholds in its official docs as of the policy date.

  • Rate-limit headers: Unknown

  • Retry-After header: Unknown

  • Rate-limit notes: HTTP 429 is returned when limits are exceeded. Specific per-plan limits and header names are not documented publicly.

  • Pagination method: cursor

  • Default page size: 100

  • Max page size: 100

  • Pagination pointer: pageNumber (1-based integer); some endpoints use a cursor token returned in the response body as 'nextPageNumber'.

  • Webhooks available: No

  • Webhook notes: Abnormal Security does not document a native outbound webhook system in its public API reference as of the policy date.

  • Alternative event strategy: Use polling on /v1/threats or /v1/cases with a timestamp or pageNumber cursor to detect new events. SIEM integrations (Splunk, Microsoft Sentinel) are available via pre-built connectors in the Abnormal portal.

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: N/A
  • Endpoint: Not documented

Limitations:

  • Abnormal Security does not expose a SCIM 2.0 endpoint for user provisioning or deprovisioning.
  • User identity data is ingested read-only from the connected mail environment (Microsoft 365 or Google Workspace); it is not managed via SCIM.
  • SSO via Okta or Entra ID is supported for portal login but does not include SCIM provisioning.

Common scenarios

Three primary automation scenarios are supported by the current API surface.

First, enumerating high-risk accounts: paginate GET /v1/accounts, filter on riskScore == 'high', then hydrate each match with GET /v1/accounts/{email} (URL-encode the @ as %40) to retrieve department, title, and isVip for downstream identity graph enrichment or security review routing.

Second, pulling open ATO cases per user: call GET /v1/accounts/{email}/cases, filter for status == 'Open', then fetch full investigation detail via GET /v1/cases/{caseId}

this endpoint returns only ATO-type cases, not phishing message threats.

Third, polling for new threats: since no server-side recipient or date-range filter exists on GET /v1/threats, client-side filtering against recipientAddress and receivedTime is required, which can be expensive for large tenants.

The /v1/vendors/{vendorDomain} endpoint is gated behind the Vendor Email Compromise licensed module and will return HTTP 403 without it.

Identify high-risk employees for security review

  1. GET /v1/accounts?pageNumber=1 to retrieve all observed accounts.
  2. Paginate through all pages using the 'nextPageNumber' field until it is null.
  3. Filter the resulting list for records where riskScore == 'high'.
  4. For each high-risk email, call GET /v1/accounts/{email} to retrieve full profile including department and title.
  5. Cross-reference with your HR system or IdP to initiate a security review workflow.

Watch out for: riskScore values and their exact string representations should be validated against the live API response; the API does not expose an enum list in the public docs.

Pull open ATO cases for a specific user

  1. Call GET /v1/accounts/{email}/cases using the URL-encoded employee email.
  2. Filter returned cases where status == 'Open'.
  3. For each open caseId, call GET /v1/cases/{caseId} to retrieve full investigation details including firstObserved and severity.
  4. Feed case data into your SIEM or ticketing system.

Watch out for: Cases endpoint returns only ATO-type investigations linked to the account, not phishing message threats. Use /v1/threats filtered by recipient for message-level data.

Poll for new threats targeting a specific recipient

  1. Call GET /v1/threats?pageNumber=1 and record the most recent 'receivedTime' from the response.
  2. On subsequent polls, retrieve pages and stop pagination when 'receivedTime' is older than the last recorded timestamp.
  3. Filter threats where 'recipientAddress' matches the target user email.
  4. Store new threat IDs and call GET /v1/threats/{threatId} for full details as needed.

Watch out for: There is no server-side filter parameter for recipient or date range on the /v1/threats list endpoint; client-side filtering is required, which may be expensive for large tenants.

Why building this yourself is a trap

The most consequential caveat for integration architects is that Abnormal's account objects are an observed, read-only reflection of the mail environment - not a canonical identity directory. The API cannot be used to provision, deprovision, or modify user records, and account presence in the API does not confirm active employment or current access rights.

For identity graph construction, treat Abnormal data as a risk-signal enrichment layer: riskScore, riskLevel, compromisedSince, and isVip are high-value fields to join against your IdP's user records, but the join key (email) must be URL-encoded in every path parameter. Webhooks are not natively supported;

all event detection requires polling, and no public deprecation timeline exists for the v1 API path.

Automate Abnormal Security workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 17, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste

Adyen logo

Adyen

API Only
AutomationAPI only
Last updatedFeb 2026

Adyen user management is handled entirely through the Customer Area (Settings > Users) using a predefined role-based access control model. There are no custom roles — all roles are defined by Adyen, and admins can only assign roles they themselves alre