Stitchflow
Veeva PromoMats logo

Veeva PromoMats User Management API Guide

API workflow

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

UpdatedMar 18, 2026

Summary and recommendation

The Veeva Vault REST API (v24.3) exposes full user lifecycle management - create, read, update, and deactivate - under the /objects/users path.

There is no PromoMats-specific API layer;

all calls target the standard Vault REST API, with the vault subdomain and object types differentiating PromoMats vaults from other Vault products.

Authentication supports either session-based tokens (POST /auth) or OAuth 2.0 via a Connected App;

note that session IDs are passed as a raw Authorization header value with no 'Bearer' prefix, unlike standard OAuth bearer tokens - mixing these up returns a 401.

SCIM 2.0 is available at /scim/v2 on Enterprise plans, supporting GET, POST, PUT, PATCH, and DELETE (which maps to deactivation, not hard deletion).

SCIM tokens are long-lived OAuth 2.0 bearer tokens generated separately in Vault Admin and are distinct from session tokens.

For identity graph use cases - syncing PromoMats user state into a downstream directory or IDP - SCIM is the preferred integration surface;

the REST API's VQL query endpoint is the fallback for delta-sync patterns where SCIM is unavailable.

Rate limits are 200 calls per 5-minute window per session and 500,000 calls per vault per day.

The API does not return rate-limit headers or a Retry-After header;

implement exponential backoff on HTTP 429.

API versioning is explicit in the URL path and Veeva increments versions on a roughly twice-yearly release cadence - always pin to a supported version and monitor the deprecation schedule.

API quick reference

Has user APIYes
Auth methodSession ID (username/password) or OAuth 2.0 / OpenID Connect. Session ID is obtained via POST to /auth; OAuth 2.0 is supported for connected app integrations.
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredEnterprise

Authentication

Auth method: Session ID (username/password) or OAuth 2.0 / OpenID Connect. Session ID is obtained via POST to /auth; OAuth 2.0 is supported for connected app integrations.

Setup steps

  1. Option A – Session Auth: POST credentials to https://{vault_domain}.veevavault.com/api/v24.3/auth with username and password; extract sessionId from response.
  2. Option B – OAuth 2.0: Register a Connected App in Vault Admin > OAuth 2.0 / OpenID Connect; obtain client_id and configure authorization server; exchange authorization code or client credentials for a bearer token.
  3. Pass the session ID as the Authorization header value (no 'Bearer' prefix for session tokens) or pass OAuth bearer token as 'Authorization: Bearer {token}'.
  4. All requests must use HTTPS; HTTP is not supported.

Required scopes

Scope Description Required for
vault_owner or admin role Vault-level administrative role required to create, update, deactivate, or retrieve users via API. All user management operations
Connected App OAuth scope (vault-specific) When using OAuth 2.0 Connected Apps, the app must be granted access to the target vault and appropriate user-management permissions. OAuth 2.0 authenticated user management

User object / data model

Field Type Description On create On update Notes
id string Unique Vault user ID system-generated read-only Numeric string assigned by Vault
user_name__v string Username (typically email address) required optional Must be unique within the vault
user_first_name__v string User's first name required optional
user_last_name__v string User's last name required optional
user_email__v string User's email address required optional Used for notifications and login
user_timezone__v string User's timezone (e.g., America/New_York) optional optional
user_locale__v string User's locale setting (e.g., en_US) optional optional
user_language__v string User's preferred language optional optional
license_type__v string Vault license type assigned to user (e.g., full__v, read_only__v, external__v) required optional Affects billing and feature access
security_profile__v string Security profile name controlling permissions required optional Must reference an existing security profile in the vault
user_title__v string User's job title optional optional
department__v string User's department optional optional
company__v string User's company name optional optional
active__v boolean Whether the user account is active optional (defaults true) optional Set to false to deactivate; Vault does not support hard-delete of users
federated_id__v string External identity provider subject identifier for SSO optional optional Required when using SAML/OIDC SSO
domain_id__v string Vault domain ID the user belongs to optional read-only
created_date__v datetime Timestamp of user creation system-generated read-only ISO 8601 format
modified_date__v datetime Timestamp of last modification system-generated system-generated ISO 8601 format

Core endpoints

Authenticate / Create Session

  • Method: POST
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/auth
  • Watch out for: Session tokens expire after inactivity. Re-authenticate programmatically; do not cache indefinitely.

Request example

POST /api/v24.3/auth
Content-Type: application/x-www-form-urlencoded

username=admin%40example.com&password=secret

Response example

{
  "responseStatus": "SUCCESS",
  "sessionId": "ABC123sessiontoken",
  "userId": 12345,
  "vaultId": 1001
}

List All Users

  • Method: GET
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/objects/users
  • Watch out for: Returns all users including inactive. Filter active__v client-side or use query endpoint for server-side filtering.

Request example

GET /api/v24.3/objects/users?limit=200&offset=0
Authorization: {sessionId}

Response example

{
  "responseStatus": "SUCCESS",
  "users": [
    {"user": {"id": "12345", "user_name__v": "jane@example.com", "active__v": true}}
  ],
  "responseDetails": {"total": 450, "offset": 0, "limit": 200}
}

Retrieve Single User

  • Method: GET
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/objects/users/{user_id}
  • Watch out for: Use numeric user ID, not username. Retrieve the ID from the list endpoint first.

Request example

GET /api/v24.3/objects/users/12345
Authorization: {sessionId}

Response example

{
  "responseStatus": "SUCCESS",
  "users": [{
    "user": {
      "id": "12345",
      "user_name__v": "jane@example.com",
      "license_type__v": "full__v"
    }
  }]
}

Create User

  • Method: POST
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/objects/users
  • Watch out for: license_type__v and security_profile__v are required. Invalid values return a PARAMETER_REQUIRED or INVALID_DATA error with no partial creation.

Request example

POST /api/v24.3/objects/users
Authorization: {sessionId}
Content-Type: application/json

{"user_name__v":"new@example.com","user_first_name__v":"Jane","user_last_name__v":"Doe","user_email__v":"new@example.com","license_type__v":"full__v","security_profile__v":"vault_owner__v"}

Response example

{
  "responseStatus": "SUCCESS",
  "id": 67890
}

Update User

  • Method: PUT
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/objects/users/{user_id}
  • Watch out for: PUT replaces only the fields provided; omitted fields retain existing values. However, required fields must still be valid if included.

Request example

PUT /api/v24.3/objects/users/67890
Authorization: {sessionId}
Content-Type: application/json

{"user_title__v":"Senior Manager","department__v":"Marketing"}

Response example

{
  "responseStatus": "SUCCESS",
  "id": 67890
}

Deactivate User

  • Method: PUT
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/objects/users/{user_id}
  • Watch out for: Vault does not support hard-deletion of users. Deactivation (active__v=false) is the only supported offboarding action via API.

Request example

PUT /api/v24.3/objects/users/67890
Authorization: {sessionId}
Content-Type: application/json

{"active__v": false}

Response example

{
  "responseStatus": "SUCCESS",
  "id": 67890
}

Retrieve Current User (Me)

  • Method: GET
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/objects/users/me
  • Watch out for: Useful for validating session credentials and retrieving the authenticated integration user's ID.

Request example

GET /api/v24.3/objects/users/me
Authorization: {sessionId}

Response example

{
  "responseStatus": "SUCCESS",
  "users": [{
    "user": {"id": "12345", "user_name__v": "api_user@example.com"}
  }]
}

Query Users via VQL

  • Method: GET
  • URL: https://{vault_domain}.veevavault.com/api/v24.3/query
  • Watch out for: VQL (Vault Query Language) is SQL-like but not SQL. Unsupported SQL clauses (e.g., JOIN across unrelated objects) will return errors. URL-encode the q parameter.

Request example

GET /api/v24.3/query?q=SELECT+id,user_name__v,active__v+FROM+users+WHERE+active__v%3Dtrue
Authorization: {sessionId}

Response example

{
  "responseStatus": "SUCCESS",
  "responseDetails": {"total": 120},
  "data": [
    {"id": "12345", "user_name__v": "jane@example.com", "active__v": true}
  ]
}

Rate limits, pagination, and events

  • Rate limits: Veeva Vault enforces API burst and daily limits. The official docs specify a burst limit of 200 API calls per 5-minute window per user session, and a daily limit of 500,000 API calls per vault. Limits apply across all Vault REST API endpoints.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: The official API docs do not document rate-limit response headers or a Retry-After header. When limits are exceeded, the API returns HTTP 429. Vault recommends implementing exponential backoff.
  • Pagination method: offset
  • Default page size: 200
  • Max page size: 1000
  • Pagination pointer: offset and limit query parameters; response includes responseDetails.next_page URL when additional records exist
Plan Limit Concurrent
All Vault plans (including PromoMats) 200 calls per 5-minute window per session; 500,000 calls per vault per day 0
  • Webhooks available: No
  • Webhook notes: Veeva Vault does not offer outbound webhooks for user lifecycle events in the traditional sense. Vault supports 'Vault Actions' and workflow notifications internally, but there is no documented push-webhook mechanism for user create/update/deactivate events to external systems.
  • Alternative event strategy: Poll the /objects/users endpoint on a schedule using modified_date__v filtering via VQL to detect changes. Vault also supports Spark Messaging (internal event bus) for vault-to-vault integrations, but this is not a general-purpose external webhook system.

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Enterprise

  • Endpoint: https://{vault_domain}.veevavault.com/scim/v2

  • Supported operations: GET /Users – list users, GET /Users/{id} – retrieve user, POST /Users – create user, PUT /Users/{id} – replace user, PATCH /Users/{id} – update user, DELETE /Users/{id} – deactivate user, GET /ServiceProviderConfig, GET /Schemas

Limitations:

  • SCIM DELETE maps to deactivation (active=false), not hard deletion, consistent with Vault's user model.
  • SCIM endpoint availability requires Enterprise plan; not available on lower tiers per context data.
  • SCIM provisioning typically requires configuration through an IdP (e.g., Okta, Azure AD) using the Vault SCIM base URL and a dedicated SCIM OAuth token.
  • Group provisioning support via SCIM /Groups endpoint availability should be verified against current Vault release notes as it may be limited.
  • The SCIM token is a long-lived OAuth 2.0 bearer token generated in Vault Admin; it is separate from session-based API tokens.

Common scenarios

Three core automation scenarios are well-supported by the API:

  • Provisioning: POST to /objects/users with user_name__v, license_type__v, and security_profile__v as required fields. Retrieve valid license type and security profile values first via GET /objects/users/license_types and GET /objects/securityprofiles - submitting an unrecognized value returns INVALID_DATA with no partial creation. Bulk provisioning is supported via multipart/form-data CSV upload; the standard JSON endpoint is single-record only.

  • Delta sync for identity graph population: Query via VQL (GET /query) with a WHERE modified_date__v > '{last_sync_timestamp}' clause to retrieve only changed user records. Paginate with offset/limit parameters; continue until responseDetails.next_page is absent. VQL timestamps must be ISO 8601 UTC and URL-encoded - the FROM clause uses 'users' (no __v suffix), unlike the object API path.

  • Offboarding: PUT to /objects/users/{user_id} with active__v=false. Hard deletion is not supported anywhere in the Vault API; deactivation is the only offboarding action. Reactivation via active__v=true is possible and immediately resumes license consumption. Verify the state change with a follow-up GET before closing the offboarding ticket.

Onboard a new PromoMats user via REST API

  1. POST to /auth with admin credentials to obtain a sessionId.
  2. POST to /objects/users with required fields: user_name__v, user_first_name__v, user_last_name__v, user_email__v, license_type__v, security_profile__v.
  3. Capture the returned numeric user id from the response.
  4. Optionally assign the user to groups via PUT /objects/groups/{group_id} to add the user ID to the group's membership.

Watch out for: If license_type__v or security_profile__v values do not exactly match vault-configured values, the API returns INVALID_DATA with no partial creation. Retrieve valid values first via GET /objects/users/license_types and GET /objects/securityprofiles.

Sync active users from PromoMats to an external directory

  1. Authenticate and obtain sessionId.
  2. Issue a VQL query: GET /query?q=SELECT id,user_name__v,user_email__v,active__v,modified_date__v FROM users WHERE active__v=true
  3. Paginate using offset/limit until responseDetails.next_page is absent.
  4. Store modified_date__v per user; on subsequent syncs, add WHERE modified_date__v > '{last_sync_timestamp}' to retrieve only changed records.

Watch out for: VQL timestamps must be in ISO 8601 UTC format and URL-encoded. The FROM clause uses 'users' (lowercase, no __v suffix) in VQL, unlike object API paths.

Offboard a departing user

  1. Authenticate and obtain sessionId.
  2. If only the username is known, query via VQL: SELECT id FROM users WHERE user_name__v='departing@example.com' to get the numeric user ID.
  3. PUT to /objects/users/{user_id} with body {"active__v": false} to deactivate the account.
  4. Verify deactivation by GET /objects/users/{user_id} and confirming active__v is false in the response.

Watch out for: Deactivation is irreversible via standard API in the sense that content ownership and audit history are retained. Reactivation is possible by setting active__v=true, but license consumption resumes immediately.

Why building this yourself is a trap

The most consequential caveat for integrators is that Veeva Vault has no outbound webhook mechanism for user lifecycle events. There is no push notification when a user is created, updated, or deactivated - external systems must poll /objects/users on a schedule.

Vault's internal Spark Messaging bus handles vault-to-vault events but is not a general-purpose external webhook system.

Two additional traps are worth flagging explicitly. First, session tokens expire on inactivity and must be re-authenticated programmatically; do not cache them indefinitely.

Running parallel sessions multiplies effective throughput against the per-session rate limit but accelerates consumption of the vault-level daily cap.

Second, the vault subdomain is instance-specific and must be retrieved from Vault Admin or via API endpoint discovery - there is no single global base URL, which complicates multi-vault identity graph designs where PromoMats is one node among several Vault products.

Automate Veeva PromoMats 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 18, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen