Summary and recommendation
The VictorOps REST API authenticates via two org-scoped HTTP headers - X-VO-Api-Id and X-VO-Api-Key - on every request to https://api.victorops.com/api-public/v1.
There is no OAuth 2.0 or Bearer token flow;
the API Key grants full admin-level access to the org and must be treated as a high-privilege secret.
Rate limit thresholds are enforced but not publicly documented;
no Retry-After header behavior is specified in official docs - contact Splunk On-Call support for current limits.
List endpoints such as GET /api-public/v1/user return all records in a single response with no pagination support, which is a practical concern for large orgs.
Key user object fields include username (immutable, used as the path parameter in all per-user calls), firstName, lastName, email, admin (boolean), verified (boolean), and createdAt (ISO 8601).
PUT /api-public/v1/user/{user} uses full-replacement semantics - omitting optional fields may reset them.
DELETE /api-public/v1/user/{user} is permanent and immediately removes the user from all teams and on-call rotations with no soft-delete equivalent via the REST API.
Webhooks for user lifecycle events do not exist;
outbound webhooks are scoped to incident and alert events only.
To detect roster changes programmatically, poll GET /api-public/v1/user on a schedule or use SCIM provisioning if the org is on Enterprise with SSO configured.
API quick reference
| Has user API | Yes |
| Auth method | API ID + API Key passed as HTTP headers (X-VO-Api-Id and X-VO-Api-Key) |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | Enterprise |
Authentication
Auth method: API ID + API Key passed as HTTP headers (X-VO-Api-Id and X-VO-Api-Key)
Setup steps
- Log in to the VictorOps (Splunk On-Call) web portal as an Admin.
- Navigate to Integrations > API in the left sidebar.
- Copy your organization's API ID (X-VO-Api-Id).
- Generate or copy an API Key (X-VO-Api-Key) from the same page.
- Include both values as HTTP headers on every API request.
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| username | string | Unique username for the user | required | immutable | Used as the primary identifier in URL paths |
| firstName | string | User's first name | required | optional | |
| lastName | string | User's last name | required | optional | |
| string | User's email address | required | optional | Used for notifications and login | |
| admin | boolean | Whether the user has admin privileges | optional | optional | |
| createdAt | string (ISO 8601) | Timestamp when the user was created | read-only | read-only | |
| passwordLastUpdated | string (ISO 8601) | Timestamp of last password update | read-only | read-only | |
| verified | boolean | Whether the user's email has been verified | read-only | read-only | |
| _selfUrl | string | Hypermedia link to the user resource | read-only | read-only |
Core endpoints
List all users
- Method: GET
- URL:
https://api.victorops.com/api-public/v1/user - Watch out for: Returns all users in the org; no pagination parameters are supported.
Request example
GET /api-public/v1/user
X-VO-Api-Id: your-api-id
X-VO-Api-Key: your-api-key
Response example
{
"users": [
{"username":"jdoe","firstName":"Jane","lastName":"Doe","email":"jdoe@example.com","admin":false}
],
"_selfUrl": "/api-public/v1/user"
}
Get a single user
- Method: GET
- URL:
https://api.victorops.com/api-public/v1/user/{user} - Watch out for: The {user} path parameter is the username string, not a numeric ID.
Request example
GET /api-public/v1/user/jdoe
X-VO-Api-Id: your-api-id
X-VO-Api-Key: your-api-key
Response example
{
"username": "jdoe",
"firstName": "Jane",
"lastName": "Doe",
"email": "jdoe@example.com",
"admin": false,
"verified": true
}
Create a user
- Method: POST
- URL:
https://api.victorops.com/api-public/v1/user - Watch out for: Username must be unique across the org and cannot be changed after creation.
Request example
POST /api-public/v1/user
Content-Type: application/json
{"firstName":"Jane","lastName":"Doe","username":"jdoe","email":"jdoe@example.com"}
Response example
{
"username": "jdoe",
"firstName": "Jane",
"lastName": "Doe",
"email": "jdoe@example.com",
"admin": false
}
Update a user
- Method: PUT
- URL:
https://api.victorops.com/api-public/v1/user/{user} - Watch out for: Full PUT semantics; omitting optional fields may reset them. Username is immutable.
Request example
PUT /api-public/v1/user/jdoe
Content-Type: application/json
{"firstName":"Janet","lastName":"Doe","email":"janet@example.com"}
Response example
{
"username": "jdoe",
"firstName": "Janet",
"lastName": "Doe",
"email": "janet@example.com"
}
Delete a user
- Method: DELETE
- URL:
https://api.victorops.com/api-public/v1/user/{user} - Watch out for: Deleting a user removes them from all teams and on-call schedules. This action is irreversible.
Request example
DELETE /api-public/v1/user/jdoe
X-VO-Api-Id: your-api-id
X-VO-Api-Key: your-api-key
Response example
{
"result": "success"
}
Get user's team memberships
- Method: GET
- URL:
https://api.victorops.com/api-public/v1/user/{user}/teams - Watch out for: Returns team slugs, not human-readable names alone; use the team slug for subsequent team API calls.
Request example
GET /api-public/v1/user/jdoe/teams
X-VO-Api-Id: your-api-id
X-VO-Api-Key: your-api-key
Response example
{
"teams": [
{"name":"ops-team","slug":"team-abc123","_selfUrl":"/api-public/v1/team/team-abc123"}
]
}
Add user to a team
- Method: POST
- URL:
https://api.victorops.com/api-public/v1/team/{team}/members - Watch out for: The {team} parameter is the team slug, not the display name.
Request example
POST /api-public/v1/team/team-abc123/members
Content-Type: application/json
{"username":"jdoe"}
Response example
{
"result": "success"
}
Remove user from a team
- Method: DELETE
- URL:
https://api.victorops.com/api-public/v1/team/{team}/members/{user} - Watch out for: Removing a user from a team does not delete the user from the org; they remain in other teams and the org roster.
Request example
DELETE /api-public/v1/team/team-abc123/members/jdoe
X-VO-Api-Id: your-api-id
X-VO-Api-Key: your-api-key
Response example
{
"result": "success"
}
Rate limits, pagination, and events
Rate limits: VictorOps enforces rate limits on API requests but does not publicly document specific numeric thresholds in official docs.
Rate-limit headers: Unknown
Retry-After header: Unknown
Rate-limit notes: Official docs do not specify per-plan rate limit tiers, header names, or Retry-After behavior. Contact Splunk On-Call support for current limits.
Pagination method: none
Default page size: 0
Max page size: 0
Pagination pointer: Not documented
Webhooks available: No
Webhook notes: VictorOps does not offer outbound webhooks specifically for user-management lifecycle events (create/update/delete). Outbound webhooks exist for incident/alert events only.
Alternative event strategy: Poll GET /api-public/v1/user on a schedule to detect roster changes, or use SCIM provisioning for automated lifecycle management via an IdP.
SCIM API status
SCIM available: No
SCIM version: 2.0
Plan required: Enterprise
Endpoint: Not documented
Supported operations: Create user, Update user, Deactivate user, List users
Limitations:
- Requires Enterprise plan.
- SSO must be configured as a prerequisite before SCIM can be enabled.
- SCIM endpoint URL and bearer token are generated within the IdP integration (e.g., Okta, Entra ID, OneLogin); no generic static endpoint is published in official docs.
- Google Workspace is not listed as a supported IdP for SCIM.
- Group/team provisioning support is not documented in official help articles.
Common scenarios
Provisioning a new on-call engineer requires two sequential calls: POST /api-public/v1/user to create the account (firstName, lastName, username, email required), then POST /api-public/v1/team/{team-slug}/members to assign team membership.
The {team-slug} is the slug identifier, not the display name - retrieve it first via GET /api-public/v1/team if unknown.
The new user is not active for on-call until they verify their email via the invitation link.
Offboarding requires explicit sequencing to avoid broken escalation policy references.
First call GET /api-public/v1/user/{username}/teams to enumerate memberships, then DELETE /api-public/v1/team/{team-slug}/members/{username} for each team.
Audit escalation policies before issuing DELETE /api-public/v1/user/{username} - deleting the user first may leave dangling policy references with no automated cleanup.
For Enterprise orgs with SSO active, SCIM provisioning via an IdP (Okta, Entra ID, OneLogin) is the recommended path for lifecycle automation and integrates cleanly into an identity graph that maps users across systems.
The SCIM endpoint URL and bearer token are generated inside the VictorOps admin portal after enabling SCIM - they are not static public values.
Google Workspace is not listed as a supported SCIM IdP, and group/team provisioning support is not documented in official help articles.
Provision a new on-call engineer and add them to a team
- POST /api-public/v1/user with firstName, lastName, username, and email to create the user account.
- Capture the username from the response.
- Retrieve the target team's slug via GET /api-public/v1/team if not already known.
- POST /api-public/v1/team/{team-slug}/members with {"username": "
"} to add the user to the team.
Watch out for: The new user will receive an email invitation to set their password. They are not active for on-call until they verify their email.
Offboard a departing user
- GET /api-public/v1/user/{username}/teams to identify all team memberships.
- For each team, DELETE /api-public/v1/team/{team-slug}/members/{username} to remove from on-call rotations.
- Verify escalation policies are updated manually in the UI or via escalation policy API endpoints.
- DELETE /api-public/v1/user/{username} to remove the user from the org.
Watch out for: Deleting the user before removing them from escalation policies may leave broken policy references. Always audit escalation policies after deletion.
Sync users from an IdP using SCIM (Enterprise)
- Confirm the org is on the Enterprise plan and SSO is already configured.
- In the VictorOps/Splunk On-Call admin portal, navigate to the SCIM provisioning settings and generate a SCIM bearer token.
- In the IdP (e.g., Okta), configure the Splunk On-Call SCIM app with the tenant URL and bearer token provided in the portal.
- Assign users and groups in the IdP to the Splunk On-Call application to trigger provisioning.
- Test provisioning by assigning a single test user and verifying creation in the VictorOps user roster.
Watch out for: The SCIM endpoint URL is provided by VictorOps inside the admin portal after enabling SCIM; it is not a static public URL. Do not use the REST API base URL as the SCIM endpoint.
Why building this yourself is a trap
The most consequential caveat in the VictorOps API is that usernames are immutable after creation.
Any automation layer or identity graph that maps VictorOps users to upstream IdP records must treat the username as a permanent, carefully chosen key - a naming convention mistake requires deactivating and recreating the user record, resetting team memberships in the process. The org-scoped API Key has no scope restrictions;
a leaked key exposes full admin access including user deletion and escalation policy modification. SCIM provisioning - the safer, event-driven alternative - is gated behind both an Enterprise plan and a fully configured SSO integration, meaning it cannot be enabled as a standalone capability.
Teams that delete users via the API before auditing escalation policies will encounter silent coverage gaps that the platform does not surface automatically.
Automate VictorOps 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.