Stitchflow
Contrast Security logo

Contrast Security User Management API Guide

API workflow

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

UpdatedMar 16, 2026

Summary and recommendation

Contrast Security exposes a REST API at `https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}` for full user lifecycle management.

Authentication requires two headers on every request: `Authorization` (Base64-encoded `username:service-key`) and `API-Key` (your API key from User Settings > Your Account).

Omitting either header returns a 401 with no additional detail.

All org-scoped endpoints require the `orgUuid` path parameter, which is the organization's UUID-not its display name-retrieved from Organization Settings > General.

SuperAdmin endpoints use a separate base path (`/Contrast/api/ng/superadmin/`) and require system-level credentials;

these are only relevant for self-hosted (EOP) deployments.

API quick reference

Has user APIYes
Auth methodAPI Key + Service Key (HTTP Basic variant): Authorization header encodes username:service-key in Base64; API key passed as a separate header (API-Key).
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredEnterprise

Authentication

Auth method: API Key + Service Key (HTTP Basic variant): Authorization header encodes username:service-key in Base64; API key passed as a separate header (API-Key).

Setup steps

  1. Log in to Contrast Security and navigate to User Settings > Your Account.
  2. Copy your API Key and Service Key from the 'Your Keys' section.
  3. Obtain your Organization UUID from Organization Settings > General.
  4. For each request, set the 'Authorization' header to Base64-encoded 'username:service-key'.
  5. Set the 'API-Key' header to your API Key.
  6. Set 'Accept: application/json' and 'Content-Type: application/json' headers.

Required scopes

Scope Description Required for
Organization Admin Required to create, update, deactivate, or delete users within an organization. POST/PUT/DELETE user endpoints
View (Read) Minimum role to list or retrieve user details. GET user endpoints

User object / data model

Field Type Description On create On update Notes
user_id string Unique identifier for the user. system-assigned immutable Used in URL path for user-specific operations.
username string User's login email address. required read-only after creation Must be a valid email.
first_name string User's first name. required optional
last_name string User's last name. required optional
email string Contact email; typically same as username. required optional
enabled boolean Whether the user account is active. defaults to true optional Set to false to deactivate.
role string (enum) Organization-level role: ROLE_ADMIN, ROLE_EDIT, ROLE_RULES_ADMIN, ROLE_VIEW, ROLE_NO_ACCESS. required optional Controls permissions within the organization.
groups array Access groups the user belongs to. optional optional Group membership controls application-level access.
date_created timestamp (epoch ms) When the user was created. system-assigned immutable
last_login timestamp (epoch ms) Timestamp of most recent login. system-assigned system-managed
org_uuid string UUID of the organization the user belongs to. derived from endpoint path immutable
api_only boolean Indicates a service/API-only account with no UI access. optional optional
protect_enabled boolean Whether Contrast Protect features are enabled for this user. optional optional

Core endpoints

List organization users

  • Method: GET
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}/users
  • Watch out for: orgUuid is required in the path; using the wrong org UUID returns an empty or unauthorized response.

Request example

GET /Contrast/api/ng/{orgUuid}/users?offset=0&limit=25
Authorization: Basic <base64(user:service-key)>
API-Key: <api-key>
Accept: application/json

Response example

{
  "success": true,
  "users": [
    {"user_id":"abc123","username":"user@example.com","first_name":"Jane","last_name":"Doe","enabled":true,"role":"ROLE_EDIT"}
  ],
  "count": 1
}

Get single user

  • Method: GET
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}/users/{userId}
  • Watch out for: userId is the internal UUID, not the email address.

Request example

GET /Contrast/api/ng/{orgUuid}/users/{userId}
Authorization: Basic <base64(user:service-key)>
API-Key: <api-key>

Response example

{
  "success": true,
  "user": {
    "user_id":"abc123","username":"user@example.com","first_name":"Jane","last_name":"Doe","enabled":true,"role":"ROLE_EDIT"
  }
}

Create (invite) user

  • Method: POST
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}/users
  • Watch out for: Creating a user sends an invitation email; the account is not active until the user accepts. Requires Organization Admin role.

Request example

POST /Contrast/api/ng/{orgUuid}/users
Content-Type: application/json

{"first_name":"Jane","last_name":"Doe","email":"user@example.com","role":"ROLE_EDIT"}

Response example

{
  "success": true,
  "user": {
    "user_id":"abc123","username":"user@example.com","enabled":true
  }
}

Update user

  • Method: PUT
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}/users/{userId}
  • Watch out for: Username/email cannot be changed after account creation via API.

Request example

PUT /Contrast/api/ng/{orgUuid}/users/{userId}
Content-Type: application/json

{"first_name":"Jane","last_name":"Smith","role":"ROLE_ADMIN"}

Response example

{
  "success": true,
  "user": {
    "user_id":"abc123","role":"ROLE_ADMIN"
  }
}

Delete user

  • Method: DELETE
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}/users/{userId}
  • Watch out for: Deletion is permanent; consider disabling (enabled: false) instead for audit trail preservation.

Request example

DELETE /Contrast/api/ng/{orgUuid}/users/{userId}
Authorization: Basic <base64(user:service-key)>
API-Key: <api-key>

Response example

{
  "success": true,
  "messages": ["User deleted successfully."]
}

Get current user (self)

  • Method: GET
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/profile
  • Watch out for: This endpoint does not require orgUuid; it returns the authenticated user's profile.

Request example

GET /Contrast/api/ng/profile
Authorization: Basic <base64(user:service-key)>
API-Key: <api-key>

Response example

{
  "success": true,
  "user": {
    "username":"user@example.com","first_name":"Jane","last_name":"Doe"
  }
}

List organization roles

  • Method: GET
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}/roles
  • Watch out for: Role names are case-sensitive strings; use exact values when assigning roles to users.

Request example

GET /Contrast/api/ng/{orgUuid}/roles
Authorization: Basic <base64(user:service-key)>
API-Key: <api-key>

Response example

{
  "success": true,
  "roles": [
    {"name":"ROLE_ADMIN","description":"Organization Administrator"},
    {"name":"ROLE_EDIT","description":"Editor"}
  ]
}

Update user group membership

  • Method: PUT
  • URL: https://app.contrastsecurity.com/Contrast/api/ng/{orgUuid}/groups/{groupId}/users
  • Watch out for: Group membership controls application-level access; org-level role and group membership are separate concerns.

Request example

PUT /Contrast/api/ng/{orgUuid}/groups/{groupId}/users
Content-Type: application/json

{"users":[{"user_id":"abc123"}]}

Response example

{
  "success": true,
  "messages": ["Group membership updated."]
}

Rate limits, pagination, and events

  • Rate limits: Official documentation does not publish specific rate limit thresholds or tier-based limits.

  • Rate-limit headers: No

  • Retry-After header: No

  • Rate-limit notes: No rate limit values, headers, or Retry-After behavior documented in official sources as of research date.

  • Pagination method: offset

  • Default page size: 25

  • Max page size: Not documented

  • Pagination pointer: offset / limit (query parameters)

  • Webhooks available: No

  • Webhook notes: Official Contrast Security documentation does not describe a native webhook system for user lifecycle events.

  • Alternative event strategy: Poll the /users endpoint periodically, or use SAML SSO with JIT provisioning for automated user creation on login.

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: Enterprise
  • Endpoint: Not documented

Limitations:

  • No native SCIM 2.0 endpoint is documented by Contrast Security.
  • User provisioning via SSO uses SAML 2.0 with Just-In-Time (JIT) provisioning, not SCIM.
  • Okta and OneLogin integrations use SAML-based provisioning; no SCIM connector is published in official docs.
  • Automated deprovisioning must be handled via the REST API or manual admin action.

Common scenarios

Three scenarios cover the majority of automation use cases.

First, provisioning: POST to /users with first_name, last_name, email, and a role enum (e.g., ROLE_EDIT);

the API immediately sends an invitation email-there is no silent provisioning option.

Capture the returned user_id, then PUT to /groups/{groupId}/users to assign Access Group membership, which controls application-level access.

Note that group membership can be set before the user accepts the invitation, but access is not effective until acceptance.

Second, deprovisioning: GET /users to resolve the user's internal UUID by email, then PUT to /users/{userId} with {"enabled": false} to deactivate without deleting.

Use DELETE only when permanent removal is explicitly required, as it destroys all associated audit records.

Third, access auditing: paginate GET /users with offset and limit query parameters (default page size 25, no documented maximum), retrieve all pages client-side, then filter on last_login, enabled, and role-the API provides no server-side filtering by these fields.

Building an identity graph from this data means joining user_id, org_uuid, groups, role, enabled, and last_login across all paginated results to produce a complete picture of who has access to what and when they last used it.

Provision a new user and assign to an access group

  1. POST to /users with first_name, last_name, email, and role to create the user (invitation email sent automatically).
  2. Capture the returned user_id from the response.
  3. GET /groups to retrieve the target group's groupId.
  4. PUT to /groups/{groupId}/users with the user_id to add the user to the appropriate access group.

Watch out for: The user account is not active until the invitation email is accepted; group membership can be set before acceptance but access is not effective until then.

Deactivate a departed employee

  1. GET /users to find the user by email and retrieve their user_id.
  2. PUT to /users/{userId} with {"enabled": false} to deactivate the account without deleting it.
  3. Optionally, remove the user from all groups via PUT /groups/{groupId}/users to revoke application access immediately.

Watch out for: Disabling via 'enabled: false' preserves audit history; DELETE is permanent and removes all associated records.

Bulk-list and audit all organization users

  1. GET /users?offset=0&limit=25 to retrieve the first page; capture the total 'count' from the response.
  2. Iterate with incrementing offset values (offset=25, 50, …) until all users are retrieved.
  3. For each user, inspect 'last_login', 'enabled', and 'role' fields to identify stale or over-privileged accounts.

Watch out for: There is no server-side filtering by role or enabled status; all filtering must be done client-side after retrieval.

Why building this yourself is a trap

The most significant architectural caveat is the absence of native SCIM 2.0: there is no published SCIM endpoint, and IdP integrations (Okta, OneLogin) use SAML with JIT provisioning, which only fires on first login and does not propagate deprovisioning events. Any automated offboarding must be driven by the REST API.

Rate limits are undocumented-no thresholds, no rate-limit headers, and no Retry-After behavior are described in official sources as of the research date; build in conservative retry logic with exponential backoff. Timestamps throughout the API use epoch milliseconds, not ISO 8601, which requires explicit conversion in any downstream system.

Role values are fixed enum strings (ROLE_ADMIN, ROLE_EDIT, ROLE_RULES_ADMIN, ROLE_VIEW, ROLE_NO_ACCESS); the API returns a 400 on invalid values with no suggestion of valid options. Finally, username and email cannot be updated after account creation via the API, so identity corrections require deactivating the old account and creating a new one.

Automate Contrast 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 16, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

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