Stitchflow
Vitally logo

Vitally User Management API Guide

API workflow

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

UpdatedMar 17, 2026

Summary and recommendation

Vitally's REST API is available at https://rest.vitally.io/resources and uses HTTP Basic Auth - the API secret key is passed as the username with an empty password, Base64-encoded into the Authorization header.

Note the subdomain carefully: requests to api.vitally.io will return 404s.

The API is the only programmatic path for user lifecycle management, as Vitally exposes no SCIM 2.0 endpoint and no outbound webhooks for user-management events.

Within an identity graph, Vitally user records must always be anchored to a parent account via accountExternalId - users cannot exist as free-floating entities.

API quick reference

Has user APIYes
Auth methodHTTP Basic Auth (API secret key as username, empty password)
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredN/A

Authentication

Auth method: HTTP Basic Auth (API secret key as username, empty password)

Setup steps

  1. Log in to Vitally and navigate to Settings > Integrations > API.
  2. Generate or copy your API Secret Key.
  3. Base64-encode the string ':' (colon with empty password).
  4. Pass the encoded value in the Authorization header: 'Authorization: Basic '.

User object / data model

Field Type Description On create On update Notes
externalId string Your system's unique identifier for the user required required (used as lookup key) Must be unique per account
accountExternalId string External ID of the account this user belongs to required required Account must exist or be created first
name string Full display name of the user optional optional
email string User's email address optional optional Used for deduplication and notifications
createdAt ISO 8601 datetime string Timestamp when the user was created in your system optional optional Defaults to ingest time if omitted
traits object Key-value map of custom user attributes optional optional Trait keys must be pre-defined in Vitally settings or will be auto-created
mrr number Monthly recurring revenue attributed to the user optional optional
npsScore integer NPS score for the user (0–10) optional optional

Core endpoints

Upsert (create or update) a user

  • Method: POST
  • URL: https://rest.vitally.io/resources/users
  • Watch out for: This endpoint upserts by externalId. If the user already exists it will be updated; no separate PUT endpoint is needed.

Request example

POST /resources/users
Authorization: Basic <token>
Content-Type: application/json
{
  "externalId": "usr_123",
  "accountExternalId": "acct_456",
  "name": "Jane Doe",
  "email": "jane@example.com"
}

Response example

{
  "id": "vit_usr_abc",
  "externalId": "usr_123",
  "name": "Jane Doe",
  "email": "jane@example.com",
  "createdAt": "2024-01-15T10:00:00Z"
}

List users

  • Method: GET
  • URL: https://rest.vitally.io/resources/users
  • Watch out for: Pagination uses a 'next' cursor token. Pass it as a query param on subsequent requests to retrieve the next page.

Request example

GET /resources/users?limit=100
Authorization: Basic <token>

Response example

{
  "results": [{"id": "vit_usr_abc", "externalId": "usr_123", ...}],
  "next": "cursor_token_xyz"
}

Get a single user by externalId

  • Method: GET
  • URL: https://rest.vitally.io/resources/users/:externalId
  • Watch out for: The path parameter is your externalId, not Vitally's internal id.

Request example

GET /resources/users/usr_123
Authorization: Basic <token>

Response example

{
  "id": "vit_usr_abc",
  "externalId": "usr_123",
  "email": "jane@example.com",
  "traits": {"plan": "pro"}
}

Delete a user

  • Method: DELETE
  • URL: https://rest.vitally.io/resources/users/:externalId
  • Watch out for: Deletion is permanent. Associated events and traits are also removed.

Request example

DELETE /resources/users/usr_123
Authorization: Basic <token>

Response example

HTTP 204 No Content

Upsert an account (required before creating users)

  • Method: POST
  • URL: https://rest.vitally.io/resources/accounts
  • Watch out for: Users must reference a valid accountExternalId. Create the account first or the user upsert will fail.

Request example

POST /resources/accounts
Authorization: Basic <token>
Content-Type: application/json
{
  "externalId": "acct_456",
  "name": "Acme Corp"
}

Response example

{
  "id": "vit_acct_def",
  "externalId": "acct_456",
  "name": "Acme Corp"
}

Track a user event

  • Method: POST
  • URL: https://rest.vitally.io/resources/events
  • Watch out for: Events are tied to both user and account. Missing either externalId will cause the event to be dropped.

Request example

POST /resources/events
Authorization: Basic <token>
Content-Type: application/json
{
  "userExternalId": "usr_123",
  "accountExternalId": "acct_456",
  "event": "Feature Used",
  "timestamp": "2024-06-01T12:00:00Z"
}

Response example

HTTP 200 OK
{"status": "ok"}

List users for a specific account

  • Method: GET
  • URL: https://rest.vitally.io/resources/accounts/:accountExternalId/users
  • Watch out for: Returns only users scoped to the given account. Use the top-level /users endpoint to list across all accounts.

Request example

GET /resources/accounts/acct_456/users
Authorization: Basic <token>

Response example

{
  "results": [{"externalId": "usr_123", "email": "jane@example.com"}],
  "next": null
}

Rate limits, pagination, and events

  • Rate limits: Vitally enforces rate limits on REST API requests. Official docs note a limit of 60 requests per minute per API key.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: Official docs mention the 60 req/min limit but do not document specific rate-limit response headers or Retry-After behavior.
  • Pagination method: cursor
  • Default page size: 100
  • Max page size: 100
  • Pagination pointer: next
Plan Limit Concurrent
All plans 60 requests per minute 0
  • Webhooks available: No
  • Webhook notes: Vitally does not expose outbound webhooks from its REST API for user-management events. Data flows are primarily inbound (push to Vitally). Notifications and alerts are configured within the Vitally UI.
  • Alternative event strategy: Use Vitally's native integrations (e.g., Segment, Zapier) or poll the REST API to detect changes.

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: N/A
  • Endpoint: Not documented

Limitations:

  • Vitally does not offer a native SCIM 2.0 endpoint.
  • No IdP-native SCIM provisioning (Okta, Entra, Google Workspace, OneLogin) is documented.

Common scenarios

Three integration patterns cover the majority of use cases.

First, new-user provisioning: upsert the account via POST /resources/accounts, then upsert the user via POST /resources/users with externalId, accountExternalId, email, and traits account must exist first or the user upsert will fail.

Second, profile sync on plan or attribute change: re-POST to /resources/users with the same externalId;

traits are merged, not replaced, so set unwanted keys explicitly to null.

Third, bulk historical load: there is no batch endpoint, so each user must be upserted individually;

throttle to 60 requests per minute and implement exponential backoff on 429 responses, as no Retry-After header is documented.

Pagination across all users uses an opaque cursor token passed as the next query parameter - numeric offsets are not supported.

Provision a new user when they sign up in your product

  1. Upsert the account: POST /resources/accounts with externalId and name.
  2. Upsert the user: POST /resources/users with externalId, accountExternalId, name, email, and any relevant traits.
  3. Optionally track a 'User Signed Up' event: POST /resources/events with userExternalId, accountExternalId, event name, and timestamp.

Watch out for: Always create or upsert the account before the user. A missing accountExternalId will cause the user upsert to fail.

Sync updated user profile attributes (e.g., plan change)

  1. Construct the user payload with the updated traits object (e.g., {"plan": "enterprise"}).
  2. POST /resources/users with the same externalId and accountExternalId - the upsert will merge trait changes.
  3. Verify the response returns the updated user object.

Watch out for: Traits are merged, not replaced wholesale. To remove a trait value, explicitly set it to null in the traits object.

Bulk-load historical users from your database

  1. Export users from your database grouped by account.
  2. For each account, POST /resources/accounts to upsert it.
  3. For each user in the account, POST /resources/users with externalId, accountExternalId, email, createdAt, and traits.
  4. Throttle requests to stay under 60 req/min; implement exponential backoff on 429 responses.

Watch out for: There is no bulk/batch endpoint. Each user must be upserted individually. For large datasets, parallelize carefully while respecting the rate limit.

Why building this yourself is a trap

Several non-obvious behaviors will cause silent failures or data quality issues at scale. Custom trait keys sent via the API are auto-created in Vitally if they do not already exist, which can produce schema sprawl across the identity graph over time - establish a trait naming convention before bulk-loading.

Deleting a user via DELETE /resources/users/:externalId is permanent and removes associated event history; there is no soft-delete or deactivation state exposed through the API. Rate-limit headers are not documented, so client-side throttling logic must be implemented proactively rather than reactively.

Finally, the POST /users endpoint is a pure upsert keyed on externalId - there is no separate PATCH, and no way to distinguish a net-new create from an update in the response without querying first.

Automate Vitally 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 17, 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