Stitchflow
Sourcegraph logo

Sourcegraph User Management API Guide

API workflow

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

UpdatedMar 9, 2026

Summary and recommendation

Sourcegraph exposes user management through a single GraphQL endpoint at /.api/graphql and a SCIM 2.0 endpoint at /.api/scim/v2 (Enterprise only). All user-management operations require a site-admin personal access token with site-admin:sudo scope sent as Authorization: token <TOKEN>. Standard user tokens are rejected for any cross-user operation.

The GraphQL API returns HTTP 200 even on errors - always inspect the errors array in the response body, not the HTTP status code.

Integrating Sourcegraph into an identity graph requires treating the opaque base64-encoded user ID as the stable join key across systems; do not construct these IDs manually, always resolve them via a users query first.

API quick reference

Has user APIYes
Auth methodAccess token (Bearer) – site-admin personal access token sent as Authorization: token <TOKEN>
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredEnterprise

Authentication

Auth method: Access token (Bearer) – site-admin personal access token sent as Authorization: token

Setup steps

  1. Log in to Sourcegraph as a site administrator.
  2. Navigate to User Settings → Access tokens.
  3. Click 'Generate new token', provide a description, and select the desired permission scope (site-admin:sudo for full user management).
  4. Copy the generated token; it is shown only once.
  5. Include the token in all API requests as the HTTP header: Authorization: token .

Required scopes

Scope Description Required for
user:all Read and write access to the authenticated user's account data. Reading/updating own user profile via GraphQL
site-admin:sudo Allows acting as any user; required for site-admin user management operations. Creating, listing, updating, deleting, and promoting other users via GraphQL or SCIM

User object / data model

Field Type Description On create On update Notes
id ID (GraphQL scalar) Opaque internal user ID. system-assigned immutable Used as the primary key in all GraphQL mutations.
username string Unique login handle for the user. required updatable via updateUser mutation Must be unique across the instance; used in @-mentions.
email string Primary email address. required updatable Email verification may be required depending on site config.
displayName string Human-readable full name. optional updatable Shown in the UI; maps to SCIM displayName.
avatarURL string (URL) URL of the user's avatar image. optional updatable Can be set to a Gravatar or custom URL.
siteAdmin boolean Whether the user has site-administrator privileges. optional (default false) updatable via setUserIsSiteAdmin mutation Requires site-admin:sudo scope to promote another user.
createdAt DateTime Timestamp when the account was created. system-assigned immutable
updatedAt DateTime Timestamp of last profile update. system-assigned system-assigned
builtinAuth boolean Whether the user has a built-in (username/password) credential. depends on auth provider config read-only via API
organizations OrgConnection Organizations the user belongs to. not set at creation managed via addUserToOrganization / removeUserFromOrganization mutations Returned as a GraphQL connection.
externalAccounts ExternalAccountConnection Linked external auth provider accounts (SAML, OIDC, GitHub, etc.). system-assigned on first SSO login read-only via API Used by SCIM to correlate IdP identities.
scimExternalId string SCIM externalId assigned by the IdP. set by SCIM provisioner managed by SCIM Only present when SCIM provisioning is active.
active boolean SCIM active flag; false suspends the user. true by default updatable via SCIM PATCH or invalidateSessionsByID mutation Deactivating via SCIM revokes all sessions.

Core endpoints

List users

  • Method: POST
  • URL: https://<instance>/.api/graphql
  • Watch out for: Requires site-admin token; non-admin tokens can only query their own user.

Request example

{
  "query": "query { users(first: 20) { nodes { id username email siteAdmin } pageInfo { hasNextPage endCursor } } }"
}

Response example

{
  "data": {
    "users": {
      "nodes": [{"id":"VXNlcjox","username":"alice","email":"alice@example.com","siteAdmin":false}],
      "pageInfo": {"hasNextPage":false,"endCursor":null}
    }
  }
}

Get user by username

  • Method: POST
  • URL: https://<instance>/.api/graphql
  • Watch out for: Returns null (not an error) if the username does not exist.

Request example

{
  "query": "query { user(username: \"alice\") { id username email displayName siteAdmin createdAt } }"
}

Response example

{
  "data": {
    "user": {"id":"VXNlcjox","username":"alice","email":"alice@example.com","displayName":"Alice Smith","siteAdmin":false,"createdAt":"2024-01-10T09:00:00Z"}
  }
}

Create user (site admin)

  • Method: POST
  • URL: https://<instance>/.api/graphql
  • Watch out for: resetPasswordURL is only returned once; store it immediately. Requires site-admin:sudo scope.

Request example

{
  "query": "mutation { createUser(username: \"bob\", email: \"bob@example.com\") { user { id username } resetPasswordURL } }"
}

Response example

{
  "data": {
    "createUser": {
      "user": {"id":"VXNlcjoy","username":"bob"},
      "resetPasswordURL": "https://<instance>/password-reset?code=..."
    }
  }
}

Update user profile

  • Method: POST
  • URL: https://<instance>/.api/graphql
  • Watch out for: The mutation returns alwaysNil; success is indicated by absence of errors in the response.

Request example

{
  "query": "mutation { updateUser(user: \"VXNlcjoy\", username: \"bob2\", displayName: \"Bob Jones\") { alwaysNil } }"
}

Response example

{
  "data": { "updateUser": { "alwaysNil": null } }
}

Delete user

  • Method: POST
  • URL: https://<instance>/.api/graphql
  • Watch out for: hard: true permanently purges the user and all associated data. hard: false (soft delete) is the safer default. Irreversible for hard deletes.

Request example

{
  "query": "mutation { deleteUser(user: \"VXNlcjoy\", hard: false) { alwaysNil } }"
}

Response example

{
  "data": { "deleteUser": { "alwaysNil": null } }
}

Promote/demote site admin

  • Method: POST
  • URL: https://<instance>/.api/graphql
  • Watch out for: Cannot demote the last remaining site admin; the API will return an error.

Request example

{
  "query": "mutation { setUserIsSiteAdmin(userID: \"VXNlcjox\", siteAdmin: true) { alwaysNil } }"
}

Response example

{
  "data": { "setUserIsSiteAdmin": { "alwaysNil": null } }
}

Invalidate user sessions

  • Method: POST
  • URL: https://<instance>/.api/graphql
  • Watch out for: Forces immediate logout of all active sessions for the user. Use when deprovisioning outside of SCIM.

Request example

{
  "query": "mutation { invalidateSessionsByID(userID: \"VXNlcjox\") { alwaysNil } }"
}

Response example

{
  "data": { "invalidateSessionsByID": { "alwaysNil": null } }
}

SCIM – List users

  • Method: GET
  • URL: https://<instance>/.api/scim/v2/Users
  • Watch out for: SCIM endpoint requires Enterprise plan with SSO (SAML or OIDC) configured. The Bearer token must be a site-admin personal access token.

Request example

GET /.api/scim/v2/Users?startIndex=1&count=100
Authorization: Bearer <site-admin-token>

Response example

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  "totalResults": 2,
  "startIndex": 1,
  "itemsPerPage": 100,
  "Resources": [{"id":"VXNlcjox","userName":"alice","active":true}]
}

Rate limits, pagination, and events

  • Rate limits: Sourcegraph does not publish fixed numeric rate limits for its GraphQL API in official documentation. Rate limiting behavior is configurable by site admins via site configuration (rateLimits settings). SCIM endpoints follow standard HTTP 429 responses when limits are hit.
  • Rate-limit headers: Yes
  • Retry-After header: Yes
  • Rate-limit notes: When rate-limited, the API returns HTTP 429 with a Retry-After header. Site admins can tune limits in site config under rateLimits. Sourcegraph Cloud may enforce additional limits not publicly documented.
  • Pagination method: cursor
  • Default page size: 20
  • Max page size: 1000
  • Pagination pointer: first / after (GraphQL connection arguments); SCIM uses startIndex + count
Plan Limit Concurrent
All plans (self-hosted) Configurable by site admin; no publicly documented default ceiling 0
  • Webhooks available: No
  • Webhook notes: Sourcegraph does not offer native outbound webhooks for user lifecycle events (create, update, delete). Outbound webhooks exist for code-related events (e.g., batch changes) but not user management.
  • Alternative event strategy: Poll the GraphQL users query on a schedule, or rely on SCIM push provisioning from the IdP (Okta, Entra ID) to receive real-time user lifecycle events.

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Enterprise

  • Endpoint: https:///.api/scim/v2

  • Supported operations: GET /Users – list all users, GET /Users/{id} – get single user, POST /Users – provision new user, PUT /Users/{id} – replace user attributes, PATCH /Users/{id} – partial update (including active flag for deactivation), DELETE /Users/{id} – deprovision user, GET /ServiceProviderConfig – SCIM capability discovery, GET /Schemas – attribute schema discovery

Limitations:

  • Requires Enterprise plan; not available on Free or Enterprise Starter.
  • SSO (SAML or OIDC) must be configured and active before enabling SCIM.
  • Group provisioning (SCIM /Groups) is not supported as of the latest documented version.
  • Only Okta and Microsoft Entra ID (Azure AD) are officially documented as tested IdP integrations.
  • SCIM token must be a site-admin personal access token; no dedicated SCIM service account token type.
  • Deactivating a user via SCIM (active: false) suspends the account but does not hard-delete it.

Common scenarios

Three scenarios cover the majority of programmatic user management needs.

SCIM provisioning from Okta or Entra ID: Requires Enterprise plan, active SAML/OIDC SSO, and a site-admin token set as the scim.authToken in site config. The IdP sends POST /Users on assignment; Sourcegraph creates the account and the user authenticates via SSO immediately. If SSO is not configured before SCIM is enabled, provisioning calls succeed but the user has no login method.

Deprovision on offboarding: Preferred path is SCIM - remove the user from the IdP app assignment, which triggers PATCH active: false and optionally DELETE. For manual or scripted offboarding, call invalidateSessionsByID first to revoke all active sessions immediately, then deleteUser with hard: false for a soft delete that preserves audit history. Reserve hard: true for cases where full data purge is explicitly required; it is irreversible and removes access tokens, saved searches, and code insights.

Bulk user enumeration for identity graph reconciliation: POST to /.api/graphql with users(first: 1000) selecting id, username, email, siteAdmin, and createdAt. Paginate using the endCursor from pageInfo until hasNextPage is false. The maximum page size is 1000; omitting cursor-based pagination on large instances silently truncates results. Filter siteAdmin === false to isolate standard users for downstream processing.

Provision a new developer via SCIM from Okta

  1. Ensure Enterprise plan is active and SAML/OIDC SSO is configured in Sourcegraph site config.
  2. In Sourcegraph site config, set 'scim.authToken' to a site-admin personal access token.
  3. In Okta, add the Sourcegraph SCIM app and configure the base URL to https:///.api/scim/v2 with Bearer token auth.
  4. Assign the user to the Okta app; Okta sends POST /Users with userName, emails, displayName, and externalId.
  5. Sourcegraph creates the account; the user can log in via SSO immediately.

Watch out for: If SSO is not configured first, SCIM provisioning will succeed but the user will have no login method and cannot authenticate.

Deprovision a user when they leave the organization

  1. Via SCIM (preferred): Remove the user from the Okta/Entra app assignment; the IdP sends PATCH /Users/{id} with active: false, then optionally DELETE /Users/{id}.
  2. Via GraphQL (manual): Execute invalidateSessionsByID mutation to immediately revoke all sessions.
  3. Then execute deleteUser mutation with hard: false to soft-delete the account.
  4. Verify the user no longer appears in the users query.

Watch out for: Soft delete (hard: false) retains audit history. Hard delete (hard: true) is permanent and removes all associated data including access tokens and saved searches.

Bulk-list all users and identify non-admin accounts

  1. Send a POST to /.api/graphql with query: { users(first: 1000) { nodes { id username email siteAdmin createdAt } pageInfo { hasNextPage endCursor } } }
  2. If pageInfo.hasNextPage is true, repeat the query with after: "" until hasNextPage is false.
  3. Filter the collected nodes where siteAdmin === false to identify standard users.
  4. Use the returned IDs for subsequent update or delete mutations as needed.

Watch out for: The maximum first value is 1000 per page. For instances with more than 1000 users, cursor-based pagination is mandatory; omitting it will silently truncate results.

Why building this yourself is a trap

Several API behaviors are non-obvious and will cause silent failures if not handled explicitly. The createUser mutation returns a one-time resetPasswordURL - if not captured in the same response, a new password-reset link must be generated separately; there is no way to retrieve it again.

The updateUser mutation returns alwaysNil on success, so success detection requires checking for the absence of errors rather than a meaningful return value. SCIM /Groups is not supported; group and team membership must be managed through GraphQL organization mutations instead.

Sourcegraph Cloud instances may enforce rate limits and endpoint availability that differ from self-hosted behavior, and these are not publicly documented - Cloud-specific limits require direct engagement with Sourcegraph support.

For teams building an identity graph with 60+ deep IT/identity integrations via an MCP server, the opaque ID format and the absence of outbound user-lifecycle webhooks mean the integration layer must poll the GraphQL users query on a schedule or rely entirely on SCIM push events from the IdP for real-time state.

Automate Sourcegraph 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 9, 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