Summary and recommendation
Freshsales exposes two distinct API surfaces for user management: a REST API (base URL `https://{domain}.myfreshworks.com/crm/sales/api`) authenticated via per-user API key, and a SCIM 2.0 API (`https://{domain}.myfreshworks.com/scim/v2`) authenticated via a separate SCIM bearer token. The REST API does not provide an endpoint to create or invite net-new CRM users - that operation is SCIM-only or UI-only.
SCIM is gated behind the Enterprise plan and requires active SAML SSO configuration as a hard prerequisite; attempting to enable SCIM without SSO is unsupported. Integrating Freshsales into an identity graph requires reconciling two separate user ID namespaces: SCIM user IDs (Freshworks-internal) and CRM user IDs returned by REST endpoints - these are not interchangeable.
API quick reference
| Has user API | Yes |
| Auth method | API Key (HTTP Basic Auth: Base64-encoded 'X-API-KEY:{api_key}' or Authorization header) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: API Key (HTTP Basic Auth: Base64-encoded 'X-API-KEY:{api_key}' or Authorization header)
Setup steps
- Log in to your Freshsales account as an Admin.
- Navigate to Settings > API Settings (or Profile Settings > API Settings).
- Copy the API key displayed for your account.
- Include the API key in the Authorization header as: 'Token token={api_key}' or use HTTP Basic Auth with the key as the username and any string as the password.
- All requests must use HTTPS.
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique identifier for the sales user. | auto-generated | immutable | System-assigned. |
| string | User's email address (login identifier). | required | optional | Must be unique within the account. | |
| first_name | string | User's first name. | required | optional | |
| last_name | string | User's last name. | optional | optional | |
| display_name | string | Full display name of the user. | optional | optional | Often derived from first_name + last_name. |
| phone | string | User's phone number. | optional | optional | |
| mobile | string | User's mobile number. | optional | optional | |
| role_id | integer | ID of the role assigned to the user. | optional | optional | Roles control permissions within Freshsales. |
| territory_id | integer | ID of the territory assigned to the user. | optional | optional | |
| is_active | boolean | Whether the user account is active. | optional | optional | Deactivating a user revokes CRM access. |
| time_zone | string | User's time zone (IANA format). | optional | optional | |
| language | string | Preferred language for the user interface. | optional | optional | |
| created_at | datetime | Timestamp when the user was created. | auto-generated | immutable | ISO 8601 format. |
| updated_at | datetime | Timestamp of last update. | auto-generated | auto-updated | ISO 8601 format. |
Core endpoints
List all users
- Method: GET
- URL:
https://{domain}.myfreshworks.com/crm/sales/api/selector/owners - Watch out for: This selector endpoint returns users available as record owners. It may not return all account users or deactivated users. Use with page param for pagination.
Request example
GET /crm/sales/api/selector/owners
Authorization: Token token={api_key}
Response example
{
"users": [
{"id": 1, "name": "Jane Doe", "email": "jane@example.com", "is_active": true}
]
}
Get current authenticated user
- Method: GET
- URL:
https://{domain}.myfreshworks.com/crm/sales/api/settings/profile - Watch out for: Returns only the profile of the user whose API key is used, not arbitrary users.
Request example
GET /crm/sales/api/settings/profile
Authorization: Token token={api_key}
Response example
{
"user": {
"id": 1,
"email": "admin@example.com",
"first_name": "Jane",
"last_name": "Doe"
}
}
List roles
- Method: GET
- URL:
https://{domain}.myfreshworks.com/crm/sales/api/selector/roles - Watch out for: Role IDs are needed when assigning roles during user creation or update via SCIM.
Request example
GET /crm/sales/api/selector/roles
Authorization: Token token={api_key}
Response example
{
"roles": [
{"id": 1, "name": "Admin"},
{"id": 2, "name": "Sales Rep"}
]
}
SCIM: List users
- Method: GET
- URL:
https://{domain}.myfreshworks.com/scim/v2/Users - Watch out for: SCIM endpoint requires Enterprise plan and SAML SSO to be configured first.
Request example
GET /scim/v2/Users?startIndex=1&count=25
Authorization: Bearer {scim_token}
Response example
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 10,
"Resources": [{"id": "abc", "userName": "jane@example.com"}]
}
SCIM: Create user
- Method: POST
- URL:
https://{domain}.myfreshworks.com/scim/v2/Users - Watch out for: User provisioning via SCIM is typically managed through an IdP (Okta, Azure AD, OneLogin). Direct SCIM calls require a SCIM bearer token generated in Freshworks admin settings.
Request example
POST /scim/v2/Users
Content-Type: application/scim+json
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName":"jane@example.com",
"name":{"givenName":"Jane","familyName":"Doe"}
}
Response example
{
"id": "abc123",
"userName": "jane@example.com",
"active": true
}
SCIM: Update user (replace)
- Method: PUT
- URL:
https://{domain}.myfreshworks.com/scim/v2/Users/{id} - Watch out for: Setting active=false deactivates the user in Freshsales. Full attribute replacement (PUT) is required; PATCH support may vary by IdP integration.
Request example
PUT /scim/v2/Users/abc123
Content-Type: application/scim+json
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName":"jane@example.com",
"active": false
}
Response example
{
"id": "abc123",
"userName": "jane@example.com",
"active": false
}
SCIM: Delete user
- Method: DELETE
- URL:
https://{domain}.myfreshworks.com/scim/v2/Users/{id} - Watch out for: Deletion via SCIM may deactivate rather than permanently delete the user record in Freshsales, depending on account configuration.
Request example
DELETE /scim/v2/Users/abc123
Authorization: Bearer {scim_token}
Response example
HTTP 204 No Content
SCIM: Get user by ID
- Method: GET
- URL:
https://{domain}.myfreshworks.com/scim/v2/Users/{id} - Watch out for: SCIM user IDs are Freshworks-internal identifiers, not the same as CRM user IDs returned by the REST API.
Request example
GET /scim/v2/Users/abc123
Authorization: Bearer {scim_token}
Response example
{
"id": "abc123",
"userName": "jane@example.com",
"active": true,
"name": {"givenName": "Jane", "familyName": "Doe"}
}
Rate limits, pagination, and events
- Rate limits: Freshsales enforces rate limits per account. The documented limit is 1,000 API calls per hour per account. Exceeding the limit returns HTTP 429.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: Rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) are returned in API responses. Exact header names may vary; consult response headers at runtime.
- Pagination method: offset
- Default page size: 25
- Max page size: 100
- Pagination pointer: page
| Plan | Limit | Concurrent |
|---|---|---|
| Growth | 1000 requests/hour | 0 |
| Pro | 1000 requests/hour | 0 |
| Enterprise | 1000 requests/hour | 0 |
- Webhooks available: Yes
- Webhook notes: Freshsales supports webhooks triggered by CRM record events (contacts, deals, leads, etc.). There are no dedicated user-management webhook events (e.g., user created/deactivated).
- Alternative event strategy: For user lifecycle events, use IdP-side webhook/event notifications (e.g., Okta event hooks) in conjunction with SCIM provisioning.
- Webhook events: contact.created, contact.updated, contact.deleted, deal.created, deal.updated, deal.deleted, lead.created, lead.updated
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Endpoint: https://{domain}.myfreshworks.com/scim/v2
Supported operations: GET /Users (list), GET /Users/{id} (read), POST /Users (create), PUT /Users/{id} (replace), PATCH /Users/{id} (update), DELETE /Users/{id} (delete), GET /Groups (list), POST /Groups (create), PUT /Groups/{id} (replace), DELETE /Groups/{id} (delete)
Limitations:
- Requires Enterprise plan.
- SAML SSO must be configured before SCIM can be enabled.
- SCIM is primarily designed for use with IdPs (Okta, Azure AD/Entra ID, OneLogin); direct API usage requires generating a SCIM bearer token from Freshworks admin settings.
- Google Workspace is not listed as a supported IdP for SCIM.
- Group provisioning maps to Freshworks roles/territories; mapping behavior may vary.
- Deprovisioning behavior (deactivate vs. delete) depends on IdP configuration.
Common scenarios
Three primary automation scenarios are supported by the available API surface:
SCIM provisioning via IdP (Okta, Azure AD, OneLogin): Generate a SCIM bearer token in Freshworks Admin > Security, configure the IdP SCIM app with the base URL and token, then assign users in the IdP. The IdP sends POST /scim/v2/Users; Freshworks creates the account and dispatches an invite. Test with a single user before bulk rollout - misconfigured SSO causes silent provisioning failures.
Deactivation via SCIM: Remove or disable the user in the IdP; the IdP sends PATCH /scim/v2/Users/{id} with active=false (or DELETE, depending on IdP config). Verify with GET /scim/v2/Users/{id}. Deactivation does not reassign owned CRM records - orphaned deals and contacts must be handled separately via REST API record-update endpoints.
User roster audit via REST API: GET /crm/sales/api/selector/owners?page=1 with Authorization: Token token={api_key}, paginating until the response array is empty. This endpoint returns only active users eligible as record owners. For a complete roster including deactivated accounts, use GET /scim/v2/Users - which requires Enterprise and an active SCIM token.
Provision a new sales rep via SCIM (Okta)
- Ensure Freshsales Enterprise plan is active and SAML SSO is configured with Okta.
- In Freshworks Admin > Security, enable SCIM and copy the SCIM bearer token.
- In Okta, configure the Freshworks SCIM app with the bearer token and SCIM base URL (https://{domain}.myfreshworks.com/scim/v2).
- Assign the new user to the Freshworks app in Okta.
- Okta sends POST /scim/v2/Users with the user's attributes; Freshworks creates the account and sends an invite email.
- Verify the user appears in Freshsales Admin > Users.
Watch out for: If SSO is not fully configured before enabling SCIM, provisioning will fail silently or return errors. Test with a single user before bulk provisioning.
Deactivate a departed user via SCIM
- In the IdP (e.g., Azure AD), remove the user from the Freshworks application assignment or disable the user.
- The IdP sends PATCH /scim/v2/Users/{id} with active=false (or DELETE, depending on IdP config).
- Freshworks deactivates the user, revoking CRM access.
- Verify via GET /scim/v2/Users/{id} that active=false is reflected.
- Reassign the deactivated user's open deals/contacts to another rep via the Freshsales UI or REST API.
Watch out for: Deactivation does not automatically reassign CRM records. Orphaned records must be reassigned manually or via the REST API using the record update endpoints.
Retrieve active users for an audit via REST API
- Obtain an admin user's API key from Freshsales Settings > API Settings.
- Send GET https://{domain}.myfreshworks.com/crm/sales/api/selector/owners?page=1 with Authorization: Token token={api_key}.
- Iterate through pages (increment page param) until the returned users array is empty.
- Filter results by is_active=true to identify active users.
- Cross-reference with SCIM GET /Users for a complete roster including deactivated accounts.
Watch out for: The /selector/owners endpoint only returns active users eligible as record owners. Use SCIM GET /Users for a full user list including inactive accounts.
Why building this yourself is a trap
Several non-obvious constraints create integration risk. The /selector/owners endpoint is scoped to active record-owner-eligible users only - it will silently omit deactivated accounts and any user not eligible as an owner, making it unsuitable as a source of truth for a full identity graph without SCIM supplementation.
The 1,000 requests/hour rate limit applies per account, not per API key - multiple integrations sharing one Freshsales account share the same quota, with no per-key isolation. Domain format inconsistency is a live risk: older accounts may still resolve under {domain}.freshsales.io while newer accounts use {domain}.myfreshworks.com; hardcoding either without validation will cause auth failures.
PATCH support on SCIM PUT /Users/{id} is documented as full replacement - partial update behavior via PATCH may vary by IdP integration and should be tested explicitly. Finally, Freshsales webhooks cover CRM record events only; there are no user-lifecycle webhook events (user created, deactivated).
For event-driven identity graph updates, user lifecycle signals must come from the IdP side (e.g., Okta event hooks) rather than from Freshsales directly.
Automate Freshsales 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.