Summary and recommendation
KnowBe4 exposes two distinct API surfaces that serve different purposes and require separate credentials. The Reporting API (`https://us.api.knowbe4.com/v1`) is read-only for user records and uses a Bearer token API key generated under Account Settings > API.
SCIM 2.0 (`https://training.knowbe4.com/scim/v2`) handles all write operations - user creation, updates, and deactivation - and uses a separate token generated under Account Settings > User Management > SCIM. Conflating the two or using the wrong token for the wrong surface will produce authentication failures.
EU-region accounts must substitute `eu.api.knowbe4.com` as the Reporting API base URL; using the US endpoint for an EU account returns 401 or empty results.
Integrating KnowBe4 into an identity graph requires pulling user records, group memberships, phish-prone percentages, and training enrollment status from the Reporting API, then correlating on `email` or `employee_number` as the join key across systems.
API quick reference
| Has user API | Yes |
| Auth method | API Key (Bearer Token) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Available across KSAT plans (Silver, Gold, Platinum, Diamond); SSO must be configured as a prerequisite. |
Authentication
Auth method: API Key (Bearer Token)
Setup steps
- Log in to the KnowBe4 KSAT console as an admin.
- Navigate to Account Settings > API.
- Click 'Generate New API Key' and copy the key.
- Include the key in all requests as an HTTP header: Authorization: Bearer
. - Note: EU-region accounts use base URL https://eu.api.knowbe4.com/v1; US accounts use https://us.api.knowbe4.com/v1.
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique KnowBe4 internal user ID | system-assigned | immutable | Use this ID for user-specific API calls. |
| employee_number | string | Employee number from HR/IdP | optional | optional | |
| first_name | string | User's first name | required | optional | |
| last_name | string | User's last name | required | optional | |
| string | Primary email address (used as login) | required | optional | Must be unique within the account. | |
| phish_prone_percentage | float | User's current phish-prone percentage | read-only | read-only | Computed by KnowBe4; cannot be set via API. |
| phone_number | string | User's phone number | optional | optional | |
| extension | string | Phone extension | optional | optional | |
| mobile_phone_number | string | Mobile phone number | optional | optional | |
| location | string | Office location | optional | optional | |
| division | string | Division within the organization | optional | optional | |
| manager_name | string | Name of the user's manager | optional | optional | |
| manager_email | string | Email of the user's manager | optional | optional | |
| department | string | Department name | optional | optional | |
| organization | string | Organization/company name | optional | optional | |
| job_title | string | User's job title | optional | optional | |
| status | string | Account status: active, archived | optional | optional | Archiving a user removes them from active training without deleting records. |
| groups | array | List of group IDs the user belongs to | optional | optional | Groups are managed separately via group endpoints. |
| current_risk_score | float | User's current risk score | read-only | read-only | Computed field; not settable. |
| adi_manageable | boolean | Whether user is managed via Active Directory Integration | read-only | read-only |
Core endpoints
List Users
- Method: GET
- URL:
https://us.api.knowbe4.com/v1/users - Watch out for: Returns max 500 users per page. Iterate using the page parameter until an empty array is returned.
Request example
GET /v1/users?page=1&per_page=500
Authorization: Bearer <API_KEY>
Response example
[
{
"id": 123456,
"email": "jdoe@example.com",
"first_name": "Jane",
"last_name": "Doe",
"status": "active",
"phish_prone_percentage": 12.5
}
]
Get User by ID
- Method: GET
- URL:
https://us.api.knowbe4.com/v1/users/{id} - Watch out for: The Reporting API is primarily read-only. User creation and updates are not supported via the Reporting API; use SCIM or the KSAT console for writes.
Request example
GET /v1/users/123456
Authorization: Bearer <API_KEY>
Response example
{
"id": 123456,
"email": "jdoe@example.com",
"first_name": "Jane",
"last_name": "Doe",
"department": "Engineering",
"status": "active"
}
List Groups
- Method: GET
- URL:
https://us.api.knowbe4.com/v1/groups - Watch out for: Group membership changes must be made via the KSAT console or SCIM; the Reporting API does not support group membership writes.
Request example
GET /v1/groups?page=1&per_page=500
Authorization: Bearer <API_KEY>
Response example
[
{
"id": 789,
"name": "Engineering",
"group_type": "console_group",
"member_count": 42
}
]
Get Group Members
- Method: GET
- URL:
https://us.api.knowbe4.com/v1/groups/{id}/members - Watch out for: Pagination applies; use page parameter. Returns up to 500 members per page.
Request example
GET /v1/groups/789/members?page=1
Authorization: Bearer <API_KEY>
Response example
[
{
"id": 123456,
"email": "jdoe@example.com",
"first_name": "Jane",
"last_name": "Doe"
}
]
List Phishing Campaign Results
- Method: GET
- URL:
https://us.api.knowbe4.com/v1/phishing/campaigns - Watch out for: Per-user phishing results are available under /v1/phishing/security_tests/{pst_id}/recipients.
Request example
GET /v1/phishing/campaigns?page=1
Authorization: Bearer <API_KEY>
Response example
[
{
"campaign_id": 55,
"name": "Q1 Phish Test",
"status": "Closed",
"phish_prone_percentage": 18.2
}
]
List Training Enrollments
- Method: GET
- URL:
https://us.api.knowbe4.com/v1/training/enrollments - Watch out for: Large accounts may have tens of thousands of enrollment records; always paginate fully before processing.
Request example
GET /v1/training/enrollments?page=1
Authorization: Bearer <API_KEY>
Response example
[
{
"enrollment_id": 9001,
"user_id": 123456,
"status": "Passed",
"completion_percentage": 100
}
]
Get Account Risk Score
- Method: GET
- URL:
https://us.api.knowbe4.com/v1/account/risk_score_history - Watch out for: Account-level endpoint; not user-specific. Use /v1/users/{id} for per-user risk scores.
Request example
GET /v1/account/risk_score_history
Authorization: Bearer <API_KEY>
Response example
[
{
"risk_score": 24.3,
"date": "2024-01-15"
}
]
List Users (EU Region)
- Method: GET
- URL:
https://eu.api.knowbe4.com/v1/users - Watch out for: EU-region accounts must use the eu.api.knowbe4.com base URL. Using the US endpoint for EU accounts will return 401 or empty results.
Request example
GET /v1/users?page=1
Authorization: Bearer <API_KEY>
Response example
[
{
"id": 654321,
"email": "eu_user@example.com",
"status": "active"
}
]
Rate limits, pagination, and events
- Rate limits: KnowBe4 enforces rate limits on the Reporting API. The documented limit is 1,000 requests per minute per API key.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: When the rate limit is exceeded, the API returns HTTP 429. Headers X-RateLimit-Limit and X-RateLimit-Remaining are included in responses. Retry logic should use exponential backoff.
- Pagination method: offset
- Default page size: 500
- Max page size: 500
- Pagination pointer: page
| Plan | Limit | Concurrent |
|---|---|---|
| All plans (API key-based) | 1,000 requests per minute | 0 |
- Webhooks available: No
- Webhook notes: KnowBe4 does not offer native outbound webhooks from the KSAT platform as of the current documentation. Event-driven integrations must be achieved by polling the Reporting API.
- Alternative event strategy: Poll the Reporting API on a schedule (e.g., /v1/training/enrollments or /v1/phishing/campaigns) to detect changes. KnowBe4 integrates with SIEM tools via its API for near-real-time data export.
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Available across KSAT plans (Silver, Gold, Platinum, Diamond); SSO must be configured as a prerequisite.
Endpoint: https://training.knowbe4.com/scim/v2
Supported operations: Create User (POST /Users), Update User (PUT /Users/{id}), Deactivate/Archive User (PATCH /Users/{id} with active=false), List Users (GET /Users), Get User (GET /Users/{id}), Create Group (POST /Groups), Update Group Members (PATCH /Groups/{id}), List Groups (GET /Groups)
Limitations:
- SCIM sync is one-way: IdP pushes to KnowBe4; KnowBe4 does not push changes back to the IdP.
- SSO (SAML) must be configured before SCIM provisioning can be enabled.
- Supported IdPs with documented SCIM integration: Okta and Azure AD (Microsoft Entra ID). Other IdPs may work but are not officially documented.
- Deleting a user via SCIM archives the user in KnowBe4 rather than permanently deleting them.
- Group provisioning via SCIM maps to KnowBe4 console groups; smart groups based on attributes are not created via SCIM.
- SCIM token is generated separately from the Reporting API key within Account Settings > User Management > SCIM.
Common scenarios
Three integration patterns cover the majority of production use cases. For new-hire provisioning, configure SAML SSO in the KSAT console first, generate a SCIM token, then connect your IdP (Okta or Azure AD) to the SCIM endpoint - the IdP will POST to /scim/v2/Users for each assigned user.
For bulk user and risk data export, paginate GET /v1/users with page incremented from 1 and per_page=500 until an empty array is returned; extract email, phish_prone_percentage, and status per record.
For offboarding, remove the user from the KnowBe4 app assignment in your IdP; the IdP sends PATCH /scim/v2/Users/{id} with active=false, which archives the user and removes them from active campaigns while preserving historical phishing and training data.
Note that phish_prone_percentage and current_risk_score are computed fields - they cannot be set or overridden via API or SCIM.
Sync new hires from Okta to KnowBe4 via SCIM
- In KnowBe4 KSAT console, configure SAML SSO with Okta first (prerequisite).
- Navigate to Account Settings > User Management > SCIM and generate a SCIM token.
- In Okta Admin, add the KnowBe4 app from the Okta Integration Network and enter the SCIM base URL (https://training.knowbe4.com/scim/v2) and token.
- Assign users or groups in Okta to the KnowBe4 app; Okta will POST to /scim/v2/Users for each assigned user.
- Verify users appear in the KnowBe4 KSAT console under Users.
Watch out for: If SSO is not configured before enabling SCIM, provisioning will fail. SCIM is one-way; changes made directly in KnowBe4 console will not sync back to Okta.
Export all users and their phish-prone percentages via Reporting API
- Generate an API key in KSAT console under Account Settings > API.
- Send GET https://us.api.knowbe4.com/v1/users?page=1&per_page=500 with Authorization: Bearer
. - Collect the response array; if it contains 500 records, increment page and repeat.
- Continue until an empty array is returned.
- Extract id, email, first_name, last_name, phish_prone_percentage, and status fields from each user object.
Watch out for: Use the correct regional base URL (us vs eu). Large accounts may require dozens of paginated requests; implement retry logic for HTTP 429 responses.
Deactivate a departed employee via SCIM
- Remove the user from the KnowBe4 app assignment in your IdP (Okta or Azure AD).
- The IdP will send a PATCH /scim/v2/Users/{id} request with {"active": false} to KnowBe4.
- KnowBe4 archives the user, revoking console access and removing them from active training campaigns.
- Historical phishing and training data for the user is retained in KnowBe4 reporting.
Watch out for: Archiving is not the same as deletion; archived users still count toward historical reports. Hard deletion must be performed manually in the KSAT console if required.
Why building this yourself is a trap
The Reporting API enforces a hard pagination ceiling of 500 records per page with no cursor-based pagination; you must increment the page parameter and detect end-of-data by checking for an empty array response.
Rate limiting is set at 1,000 requests per minute per API key; HTTP 429 responses do not include a Retry-After header, so exponential backoff must be implemented manually.
API keys are account-scoped with no granular permission model - any key holder has full read access to all Reporting API data, including phishing results and risk scores, which has access-control implications for multi-team environments. No native webhooks are available; event-driven workflows must be built on polling schedules against /v1/training/enrollments or /v1/phishing/campaigns.
Stitchflow's MCP server with 60+ deep IT/identity integrations handles pagination, retry logic, and regional endpoint routing automatically, removing the most common failure points in custom Reporting API implementations.
Automate KnowBe4 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.