Summary and recommendation
Tenable Vulnerability Management exposes a REST API at https://cloud.tenable.com with full CRUD coverage for user lifecycle operations.
Authentication uses a custom X-ApiKeys header carrying an accessKey/secretKey pair not Bearer tokens or OAuth
and the API key inherits the permissions of the user who generated it, meaning only Administrator-sourced keys can create, update, or delete other users.
Core user endpoints include GET /users, POST /users, PUT /users/{id}, and DELETE /users/{id}, with offset/limit pagination supporting up to 5,000 records per page.
This API is the foundation for building identity graph integrations that map user roles, access states, and last-login signals across your broader SaaS inventory.
API quick reference
| Has user API | Yes |
| Auth method | API Key (X-ApiKeys header with accessKey and secretKey pair) |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | N/A |
Authentication
Auth method: API Key (X-ApiKeys header with accessKey and secretKey pair)
Setup steps
- Log in to Tenable.io (cloud.tenable.com) as an administrator.
- Navigate to Settings > My Account > API Keys.
- Click 'Generate' to create an accessKey and secretKey pair.
- Store both values securely; the secretKey is shown only once.
- Include both in every request header: X-ApiKeys: accessKey=
;secretKey=
Required scopes
| Scope | Description | Required for |
|---|---|---|
| Administrator role | Full access to create, update, delete, and list all users. | POST /users, PUT /users/{id}, DELETE /users/{id} |
| Standard user (self) | Can retrieve and update own user record only. | GET /users/me, PUT /users/{id} (own account) |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique numeric user identifier. | system-assigned | immutable | Used as path parameter in user-specific endpoints. |
| uuid | string (UUID) | UUID of the user. | system-assigned | immutable | Used in some newer API endpoints. |
| username | string | Login username (typically email address). | required | not updatable | Must be unique within the container. |
| string | User's email address. | required | optional | Used for notifications and login. | |
| name | string | Display name of the user. | optional | optional | Free-form full name. |
| password | string | User password. | required (non-SSO) | optional | Not returned in GET responses. |
| permissions | integer | Numeric permission level (role). 16=Basic, 24=Scan Operator, 32=Standard, 40=Scan Manager, 64=Administrator. | required | optional | Maps to named roles in the UI. |
| type | string | User type: 'local' or 'ldap'. | optional | not updatable | Defaults to 'local'. |
| enabled | boolean | Whether the user account is active. | optional (default true) | optional | Set to false to disable without deleting. |
| container_uuid | string (UUID) | UUID of the container (account) the user belongs to. | system-assigned | immutable | |
| login_name | string | The login name used for authentication. | system-assigned | immutable | Typically mirrors username. |
| last_login_attempt | integer (epoch) | Timestamp of the last login attempt. | N/A | N/A | Read-only. |
| last_login | integer (epoch) | Timestamp of the last successful login. | N/A | N/A | Read-only. |
| two_factor | object | Two-factor authentication settings (enabled, sms_enabled, email_enabled). | optional | optional | |
| role_uuid | string (UUID) | UUID of the assigned role (used in newer role-based endpoints). | optional | optional | Distinct from legacy numeric permissions field. |
Core endpoints
List users
- Method: GET
- URL:
https://cloud.tenable.com/users - Watch out for: Returns all users in the container. Requires Administrator permissions. Does not paginate by default but supports offset/limit query params.
Request example
GET /users HTTP/1.1
Host: cloud.tenable.com
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
Response example
{
"users": [
{"id": 1, "uuid": "abc-123", "username": "user@example.com",
"email": "user@example.com", "permissions": 32, "enabled": true}
]
}
Get user
- Method: GET
- URL:
https://cloud.tenable.com/users/{id} - Watch out for: {id} is the numeric integer user ID, not the UUID.
Request example
GET /users/42 HTTP/1.1
Host: cloud.tenable.com
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
Response example
{
"id": 42,
"uuid": "def-456",
"username": "admin@example.com",
"email": "admin@example.com",
"permissions": 64,
"enabled": true
}
Create user
- Method: POST
- URL:
https://cloud.tenable.com/users - Watch out for: Password is required for local users. The permissions field must be one of the documented numeric values; invalid values return 400.
Request example
POST /users HTTP/1.1
Content-Type: application/json
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
{"username":"new@example.com","password":"P@ssw0rd!","permissions":32,"email":"new@example.com","name":"New User"}
Response example
{
"id": 99,
"uuid": "ghi-789",
"username": "new@example.com",
"email": "new@example.com",
"permissions": 32,
"enabled": true
}
Update user
- Method: PUT
- URL:
https://cloud.tenable.com/users/{id} - Watch out for: Username cannot be changed after creation. Uses PUT (full-style), but only supplied fields are updated in practice.
Request example
PUT /users/99 HTTP/1.1
Content-Type: application/json
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
{"permissions":64,"name":"Updated Name","enabled":true}
Response example
{
"id": 99,
"username": "new@example.com",
"permissions": 64,
"enabled": true
}
Delete user
- Method: DELETE
- URL:
https://cloud.tenable.com/users/{id} - Watch out for: Deleting a user is permanent and cannot be undone. Disabling (enabled=false) is preferred for reversible deactivation.
Request example
DELETE /users/99 HTTP/1.1
Host: cloud.tenable.com
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
Response example
HTTP/1.1 200 OK
{}
Change user password
- Method: PUT
- URL:
https://cloud.tenable.com/users/{id}/chpasswd - Watch out for: Administrators can change any user's password. Standard users can only change their own.
Request example
PUT /users/99/chpasswd HTTP/1.1
Content-Type: application/json
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
{"password":"NewP@ssw0rd!"}
Response example
HTTP/1.1 200 OK
{}
Enable/disable two-factor authentication
- Method: PUT
- URL:
https://cloud.tenable.com/users/{id}/two-factor - Watch out for: SMS-based 2FA requires a phone number to be set on the user account first.
Request example
PUT /users/99/two-factor HTTP/1.1
Content-Type: application/json
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
{"enabled":true,"sms_enabled":false,"email_enabled":true}
Response example
HTTP/1.1 200 OK
{}
Get current user (self)
- Method: GET
- URL:
https://cloud.tenable.com/session - Watch out for: Returns the user associated with the API key in use. Useful for validating credentials and retrieving own user ID.
Request example
GET /session HTTP/1.1
Host: cloud.tenable.com
X-ApiKeys: accessKey=<ACCESS_KEY>;secretKey=<SECRET_KEY>
Response example
{
"id": 42,
"username": "me@example.com",
"email": "me@example.com",
"permissions": 64,
"container_uuid": "xyz-000"
}
Rate limits, pagination, and events
- Rate limits: Tenable enforces per-product API rate limits. For Tenable.io, the limit is 200 requests per minute per API key. Concurrent request limits also apply.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: When the rate limit is exceeded, the API returns HTTP 429. The response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers per official docs. Retry-After header is not documented as part of the 429 response.
- Pagination method: offset
- Default page size: 100
- Max page size: 5000
- Pagination pointer: offset / limit
| Plan | Limit | Concurrent |
|---|---|---|
| Tenable.io (all plans) | 200 requests/minute per API key | 10 |
- Webhooks available: No
- Webhook notes: Tenable.io does not offer native outbound webhooks for user lifecycle events (create, update, delete) via the standard API. Event-driven integrations require polling the Users API.
- Alternative event strategy: Poll GET /users on a schedule to detect changes, or use Tenable's Eventbus/SIEM integrations (e.g., Tenable One platform event exports) for broader event streaming, which is not user-management-specific.
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: N/A
- Endpoint: Not documented
Limitations:
- Tenable.io does not expose a native SCIM 2.0 endpoint.
- IdP-driven provisioning (Okta, Entra ID) is achieved via SAML SSO with JIT (Just-In-Time) provisioning, not SCIM.
- Bulk user provisioning must be done via the REST API or manual import.
Common scenarios
Three high-value automation scenarios are well-supported by the API.
First, provisioning a new analyst: POST /users with permissions set to the numeric role code (32 for Standard) and capture the returned integer id for downstream operations
note that local passwords may conflict with SAML SSO enforcement, so validate your auth policy first.
Second, deprovisioning a departing employee: locate the user's numeric id via GET /users filtered by email, then PUT /users/{id} with enabled: false for an immediately reversible soft-disable before considering a permanent DELETE
deletion can orphan scan results and policies, so disable-audit-delete is the safer sequence.
Third, role elevation: PUT /users/{id} with permissions: 64 to promote to Administrator, then confirm via a follow-up GET - the permissions field is strictly numeric;
passing a string like 'Administrator' returns a 400 error.
Provision a new analyst user
- Authenticate by including X-ApiKeys header with a valid Administrator API key.
- POST /users with body: {username, password, email, name, permissions: 32} (Standard user role).
- Capture the returned numeric 'id' for future operations.
- Optionally PUT /users/{id}/two-factor to enforce 2FA for the new account.
Watch out for: If your organization uses SAML SSO, local password-based users may be blocked from logging in via the UI. Confirm auth policy before setting a password.
Deprovision a departing employee
- GET /users to find the user's numeric ID by matching on email/username.
- PUT /users/{id} with body {enabled: false} to immediately disable access without data loss.
- Optionally DELETE /users/{id} for permanent removal after confirming no owned assets need reassignment.
Watch out for: Deleting a user may orphan scan results or policies owned by that user. Disable first, audit, then delete.
Elevate a user to Administrator
- GET /users to retrieve the target user's numeric ID.
- PUT /users/{id} with body {permissions: 64} to assign the Administrator role.
- Verify by GET /users/{id} and confirming permissions field equals 64.
Watch out for: The permissions field uses numeric codes (16, 24, 32, 40, 64). Passing a string like 'Administrator' will return a 400 error.
Why building this yourself is a trap
Several non-obvious constraints can break automation pipelines silently. The X-ApiKeys header format is exact - accessKey=
confirm the expected format per endpoint before building lookups.
The rate limit is 200 requests per minute per API key with a hard 10 concurrent request ceiling - parallel scripts sharing one key will exhaust this quickly, and the 429 response includes X-RateLimit-Reset but no Retry-After header, so retry logic must derive backoff timing from the reset timestamp.
Tenable does not offer native outbound webhooks for user lifecycle events; event-driven workflows require polling GET /users on a schedule. Tenable.sc (on-premises Security Center) uses a different base URL and session-cookie authentication entirely - it is a separate product and its API is not interchangeable with Tenable Vulnerability Management's.
Automate Tenable 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.