Stitchflow
Ashby logo

Ashby User Management API Guide

API workflow

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

UpdatedFeb 27, 2026

Summary and recommendation

Ashby exposes a REST-style API at https://api.ashbyhq.com using HTTP Basic Auth (API key as username, blank password). All endpoints - including reads - use POST; there are no GET endpoints in the public API.

Key scopes are module-level (e.g., organizationRead, organizationWrite, candidatesWrite) and are assigned per key at creation time in Admin > Integrations > API Keys. No official SDKs are provided, and no public sandbox environment exists - Ashby recommends a test workspace or restricted-key production setup for development.

Stitchflow connects to Ashby through an MCP server with ~100 deep IT/identity integrations, handling auth, pagination, and sync-token lifecycle without custom plumbing.

API quick reference

Has user APIYes
Auth methodHTTP Basic Auth (API key as username, password blank)
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredLegacy Plus, Plus, or Enterprise (not available on Foundations plan)

Authentication

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

Setup steps

  1. Log in to Ashby as an Admin and navigate to Admin > Integrations > API Keys.
  2. Create a new API key and assign module-level read/write permissions (e.g., organizationRead for user endpoints).
  3. Optionally enable 'Allow access to confidential jobs and projects?' and 'Allow access to non-offer private fields?' flags on the key.
  4. Send the API key as the HTTP Basic Auth username with every request; leave the password field blank.
  5. Set Content-Type: application/json on all requests (except multipart endpoints like applicationForm.submit).

Required scopes

Scope Description Required for
organizationRead Read access to organization/user data including user.list, user.info, user.search. Listing, fetching, and searching Ashby users
organizationWrite Write access to organization data including adding members to hiring teams. hiringTeam.addMember, application.addHiringTeamMember
candidatesRead Read access to candidate and application data. candidate.list, candidate.info, application.list, application.info
candidatesWrite Write access to candidate and application data. candidate.create, candidate.update, application.create, application.update
apiKeysRead Read access to API key metadata. apiKey.info
apiKeysWrite Write access to API key and webhook settings. webhook.create, webhook.delete
hiringProcessMetadataRead Read access to hiring process metadata including tags, archive reasons, custom fields. candidateTag.list, archiveReason.list, customField.list

User object / data model

Field Type Description On create On update Notes
id string (UUID) Unique identifier for the Ashby user. system-generated immutable Used as teamMemberId in hiring team endpoints.
firstName string User's first name. required updatable via UI
lastName string User's last name. required updatable via UI
email string User's email address; used for login and search. required editable in UI Used as the lookup key in user.search endpoint.
globalRole string (enum) User's global access level in Ashby (e.g., limitedAccess, elevatedAccess, organizationAdmin). defaults to limitedAccess updatable via UI or SCIM provisioning SCIM provisioning always sets new users to limitedAccess; role must be changed manually in Ashby after sync.
isEnabled boolean Whether the user account is active. set on activation toggled via deactivate/activate actions Deactivated users are removed from interviewer pools but remain on already-scheduled interviews.
updatedAt string (ISO 8601 datetime) Timestamp of last update to the user record. system-generated system-generated Returned in user.search and user.list responses.
includeDeactivated boolean (request param) Request parameter on user.list to include deactivated users in results. Not a field on the user object itself; a filter param for user.list.

Core endpoints

List all users

  • Method: POST
  • URL: https://api.ashbyhq.com/user.list
  • Watch out for: Requires organizationRead permission. Pass includeDeactivated: true to see deactivated/terminated users. Paginated via cursor + syncToken.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/user.list \
  -H 'Content-Type: application/json' \
  -d '{"cursor": null, "limit": 50, "includeDeactivated": false}'

Response example

{
  "success": true,
  "results": [{"id": "uuid", "firstName": "Jane", "lastName": "Doe",
    "email": "jane@example.com", "globalRole": "elevatedAccess",
    "isEnabled": true, "updatedAt": "2025-01-01T00:00:00Z"}],
  "moreDataAvailable": false,
  "nextCursor": null
}

Get user by ID

  • Method: POST
  • URL: https://api.ashbyhq.com/user.info
  • Watch out for: Requires organizationRead permission. All Ashby API calls use POST even for lookups.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/user.info \
  -H 'Content-Type: application/json' \
  -d '{"userId": "<uuid>"}'

Response example

{
  "success": true,
  "results": {"id": "uuid", "firstName": "Jane",
    "lastName": "Doe", "email": "jane@example.com",
    "globalRole": "elevatedAccess", "isEnabled": true}
}

Search user by email

  • Method: POST
  • URL: https://api.ashbyhq.com/user.search
  • Watch out for: Requires organizationRead permission. .search endpoints are not paginated; intended for specific lookups only.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/user.search \
  -H 'Content-Type: application/json' \
  -d '{"email": "jane@example.com"}'

Response example

{
  "success": true,
  "results": {"id": "uuid", "firstName": "Jane",
    "lastName": "Doe", "email": "jane@example.com",
    "globalRole": "limitedAccess", "isEnabled": true,
    "updatedAt": "2025-01-01T00:00:00Z"}
}

Add user to hiring team (job or application level)

  • Method: POST
  • URL: https://api.ashbyhq.com/hiringTeam.addMember
  • Watch out for: Requires organizationWrite permission. Must supply either applicationId or jobId (not both). roleId must be a valid UUID from the org's role list.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/hiringTeam.addMember \
  -H 'Content-Type: application/json' \
  -d '{"jobId": "<uuid>", "teamMemberId": "<uuid>", "roleId": "<uuid>"}'

Response example

{
  "success": true,
  "results": {"teamMemberId": "uuid", "roleId": "uuid",
    "jobId": "uuid"}
}

Add user to hiring team at application level

  • Method: POST
  • URL: https://api.ashbyhq.com/application.addHiringTeamMember
  • Watch out for: Requires candidateWrite permission (note: singular, not candidatesWrite). applicationId, teamMemberId, and roleId are all required UUIDs.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/application.addHiringTeamMember \
  -H 'Content-Type: application/json' \
  -d '{"applicationId": "<uuid>", "teamMemberId": "<uuid>", "roleId": "<uuid>"}'

Response example

{
  "success": true,
  "results": {"teamMemberId": "uuid", "roleId": "uuid",
    "applicationId": "uuid"}
}

Get API key info

  • Method: POST
  • URL: https://api.ashbyhq.com/apiKey.info
  • Watch out for: Requires apiKeysRead permission. Useful for verifying key identity and creation date in automated setups.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/apiKey.info \
  -H 'Content-Type: application/json' \
  -d '{}'

Response example

{
  "success": true,
  "results": {"title": "My Integration Key",
    "createdAt": "2024-06-01T00:00:00Z"}
}

Create webhook

  • Method: POST
  • URL: https://api.ashbyhq.com/webhook.create
  • Watch out for: Requires apiKeysWrite scope. A 'ping' webhook is sent on creation; if your endpoint returns >400 or times out, the webhook is created in a disabled state.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/webhook.create \
  -H 'Content-Type: application/json' \
  -d '{"webhookType": "candidateStageChange", "requestUrl": "https://your.server/hook", "secretToken": "s3cr3t"}'

Response example

{
  "success": true,
  "results": {"id": "uuid", "enabled": true,
    "requestUrl": "https://your.server/hook",
    "webhookType": "candidateStageChange"}
}

Delete webhook

  • Method: POST
  • URL: https://api.ashbyhq.com/webhook.delete
  • Watch out for: Requires apiKeysWrite permission. webhookId must be a valid UUID of an existing webhook setting.

Request example

curl -u API_KEY: -X POST https://api.ashbyhq.com/webhook.delete \
  -H 'Content-Type: application/json' \
  -d '{"webhookId": "<uuid>"}'

Response example

{
  "success": true,
  "results": {"webhookId": "uuid"}
}

Rate limits, pagination, and events

  • Rate limits: Ashby enforces rate limits per API key. Specific numeric thresholds are not publicly documented. Rate limiting is applied at the request-handling layer. Contact Ashby support for limit increases if high-volume syncs are needed.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: No official documentation of specific rate limit numbers or rate-limit response headers. Ashby's security overview confirms rate limiting exists at the request-handling layer. Reach out to support@ashbyhq.com for high-volume use cases.
  • Pagination method: cursor
  • Default page size: Not documented
  • Max page size: Not documented
  • Pagination pointer: cursor
Plan Limit Concurrent
All plans (per API key) Not publicly specified; described as 'generous' by Ashby
  • Webhooks available: Yes
  • Webhook notes: Webhooks are configured in the Ashby Admin panel (Admin > Integrations > Webhooks) or via the webhook.create API endpoint. Each webhook targets a single event type and a payload URL. An optional secret token enables HMAC signature verification via the Ashby-Signature HTTP header on incoming payloads. Some events trigger cascading related webhooks (e.g., candidateStageChange also fires applicationUpdate).
  • Alternative event strategy: Poll user.list with syncToken for incremental user sync if webhooks are not available for user-specific events.
  • Webhook events: candidateStageChange, applicationUpdate, jobPostingPublish, jobPostingUnpublish, candidateUpdate, interviewScheduleCreate, interviewScheduleUpdate, offerCreate, offerUpdate

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Legacy Plus, Plus, or Enterprise (not available on Foundations plan)

  • Endpoint: Delivered via WorkOS; specific SCIM base URL is provided by Ashby support upon setup request.

  • Supported operations: User provisioning (create), User deprovisioning (deactivate/remove), Directory sync from Okta, Microsoft Entra ID (Azure AD), Google Workspace

Limitations:

  • Permission/role mapping is not supported via SCIM; all SCIM-provisioned users are created as 'limitedAccess' and must have roles assigned manually in Ashby.
  • Log streams and domain verification are not supported.
  • SCIM setup requires contacting Ashby support (support@ashbyhq.com) to receive the WorkOS setup link; it cannot be self-served.
  • SSO must be configured alongside or before SCIM; both are delivered through WorkOS.
  • No public SCIM endpoint URL documented; provided per-customer by Ashby support.

Common scenarios

Three primary automation scenarios are well-supported by the API. First, full and incremental user sync via user.

list using cursor pagination and syncToken - note that syncToken can expire, requiring a full re-sync on sync_token_expired errors. Second, targeted user lookup by email via user.

search (non-paginated, single-record intent) followed by hiring team assignment via hiringTeam. addMember, which requires valid UUIDs for jobId, teamMemberId, and roleId.

Third, SCIM-based provisioning from Okta, Entra ID, or Google Workspace on Legacy Plus, Plus, or Enterprise plans - delivered via WorkOS, initiated by contacting support@ashbyhq. com, and limited to user create/deactivate operations with no group-to-role mapping.

Sync all active Ashby users to an external directory

  1. Create an API key with organizationRead permission in Admin > Integrations > API Keys.
  2. POST to https://api.ashbyhq.com/user.list with an empty body to retrieve the first page.
  3. If moreDataAvailable is true, pass nextCursor in subsequent requests until moreDataAvailable is false.
  4. Store the final syncToken from the last response.
  5. On subsequent syncs, pass the stored syncToken to retrieve only updated records since the last sync.
  6. If sync_token_expired error is returned, discard the token and perform a full re-sync from step 2.

Watch out for: syncToken can expire between syncs. Always handle the sync_token_expired error code and fall back to a full sync.

Look up an Ashby user by email and add them to a job's hiring team

  1. POST to https://api.ashbyhq.com/user.search with {"email": "user@example.com"} using an API key with organizationRead.
  2. Extract the id (UUID) from the response as teamMemberId.
  3. Obtain the target jobId and the desired roleId (from your org's role configuration).
  4. POST to https://api.ashbyhq.com/hiringTeam.addMember with {"jobId": "", "teamMemberId": "", "roleId": ""} using an API key with organizationWrite.

Watch out for: user.search is not paginated and is intended for specific lookups only. The roleId must be a valid UUID from the organization's configured roles, not a role name string.

Provision users via SCIM from Okta or Entra ID

  1. Confirm the Ashby account is on Legacy Plus, Plus, or Enterprise plan.
  2. Email support@ashbyhq.com requesting SCIM setup; provide the IT service account email for error notifications.
  3. Ashby support will respond with a WorkOS setup link.
  4. Complete the WorkOS SCIM configuration in your IdP (Okta, Entra ID, or Google Workspace).
  5. Assign users/groups in the IdP to push to Ashby.
  6. After provisioning, log into Ashby and manually update each new user's globalRole from limitedAccess to the appropriate permission level.

Watch out for: SCIM does not map IdP groups to Ashby permission roles. Every SCIM-provisioned user is created as limitedAccess regardless of IdP group membership. Role assignment must be done manually in Ashby after provisioning.

Why building this yourself is a trap

The most significant API caveat is that SCIM does not support permission or role mapping: every SCIM-provisioned user is created as limitedAccess regardless of IdP group assignments, and role elevation must be done manually in the Ashby admin panel after provisioning.

Rate limit thresholds are not publicly documented - Ashby confirms rate limiting exists at the request-handling layer but does not expose rate-limit response headers or retry-after values, making backoff logic implementation speculative without direct support engagement.

Confidential job and private field data are excluded from API responses by default and must be explicitly enabled per API key, meaning integrations built without these flags will silently return incomplete records.

Automate Ashby 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

UpdatedFeb 27, 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