Summary and recommendation
Namely exposes a REST API at `https://{company}.namely.com/api/v1` - the subdomain is account-specific and must match your Namely slug. Authentication supports OAuth 2.0 authorization code flow or personal access tokens (Bearer); OAuth tokens expire and require refresh_token rotation, while personal access tokens do not expire but are permanently tied to the generating user's account permissions.
If that user is deactivated, the token stops working immediately.
All response bodies wrap resources in a named array (e.g., `profiles`, `groups`) even for single-resource requests. Profile updates use PUT, not PATCH - but only fields present in the request body are modified; omitted fields are preserved. There is no hard-delete endpoint; termination is performed by setting `user_status=inactive` and providing a `departure_date` via PUT.
Pagination is offset-based using `page` and `per_page` params, with a default page size of 25 and a hard maximum of 50. Rate limits are enforced but numeric thresholds are not publicly documented; implement exponential backoff on HTTP 429 responses.
For identity graph construction, the profile object exposes `id`, `email`, `department`, `reports_to`, `office`, and `user_status` - sufficient to map organizational hierarchy and employment state, but custom HR fields are not guaranteed to be available via the standard profiles endpoint.
API quick reference
| Has user API | Yes |
| Auth method | OAuth 2.0 (authorization code flow) or personal access token (Bearer) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Unknown; SSO prerequisite required (Okta or Azure AD/Entra ID integration must be configured first) |
Authentication
Auth method: OAuth 2.0 (authorization code flow) or personal access token (Bearer)
Setup steps
- Navigate to your Namely company settings and open the API section to register an OAuth application.
- Obtain a client_id and client_secret for your registered application.
- Redirect users to https://{company}.namely.com/api/v1/oauth2/authorize with response_type=code, client_id, redirect_uri, and scope parameters.
- Exchange the returned authorization code for an access_token and refresh_token via POST to https://{company}.namely.com/api/v1/oauth2/token.
- Include the access token in all API requests as: Authorization: Bearer {access_token}.
- Alternatively, generate a personal access token from your Namely profile settings for server-to-server use without user interaction.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| read | Read access to profiles, groups, and HR data. | GET operations on profiles and related resources |
| write | Create and update profiles and HR records. | POST and PUT operations on profiles |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string | Unique Namely profile identifier (GUID). | auto-generated | immutable | Used as path parameter in profile endpoints. |
| first_name | string | Employee first name. | required | optional | |
| last_name | string | Employee last name. | required | optional | |
| string | Work email address; used as login identifier. | required | optional | Must be unique within the company. | |
| user_status | string | Employment status: active, inactive, etc. | optional | optional | Setting to inactive deactivates the user account. |
| start_date | date (YYYY-MM-DD) | Employee hire/start date. | required | optional | |
| departure_date | date (YYYY-MM-DD) | Employee termination date. | optional | optional | Setting this field triggers offboarding workflows. |
| job_title | string | Employee job title. | optional | optional | |
| department | object | Department object with id and title. | optional | optional | Reference by department id. |
| reports_to | object | Manager profile reference (id, first_name, last_name). | optional | optional | Nested profile object. |
| office | object | Office/location object with id and name. | optional | optional | |
| personal_email | string | Personal email address. | optional | optional | |
| mobile_phone | string | Mobile phone number. | optional | optional | |
| gender | string | Gender identity field. | optional | optional | |
| ethnicity | string | Ethnicity field for EEO reporting. | optional | optional | |
| salary | object | Compensation object with amount, currency, and pay_period. | optional | optional | Requires appropriate permissions to read/write. |
| groups | array | Array of group memberships (teams, departments, etc.). | optional | optional | Each group has id and type fields. |
| image | string (URL) | Profile photo URL. | optional | optional | |
| preferred_name | string | Preferred/display name. | optional | optional | |
| updated_at | datetime (ISO 8601) | Timestamp of last profile update. | auto-generated | auto-generated | Useful for delta sync filtering. |
Core endpoints
List profiles
- Method: GET
- URL:
https://{company}.namely.com/api/v1/profiles - Watch out for: Default page size is 25; max is 50. Use page and per_page params to paginate through all records.
Request example
GET /api/v1/profiles?page=1&per_page=25
Authorization: Bearer {access_token}
Response example
{
"profiles": [
{"id":"abc123","first_name":"Jane","last_name":"Doe","email":"jane@acme.com","user_status":"active"}
],
"meta": {"count":1,"total":150}
}
Get profile by ID
- Method: GET
- URL:
https://{company}.namely.com/api/v1/profiles/{id} - Watch out for: Response wraps single profile in a profiles array, not a singular object.
Request example
GET /api/v1/profiles/abc123
Authorization: Bearer {access_token}
Response example
{
"profiles": [
{"id":"abc123","first_name":"Jane","last_name":"Doe","email":"jane@acme.com","user_status":"active","start_date":"2022-01-10"}
]
}
Create profile
- Method: POST
- URL:
https://{company}.namely.com/api/v1/profiles - Watch out for: Request body must wrap the profile object inside a profiles array. Missing required fields (first_name, last_name, email, start_date) returns 422.
Request example
POST /api/v1/profiles
Authorization: Bearer {access_token}
Content-Type: application/json
{"profiles":[{"first_name":"John","last_name":"Smith","email":"john@acme.com","start_date":"2024-06-01"}]}
Response example
{
"profiles": [
{"id":"def456","first_name":"John","last_name":"Smith","email":"john@acme.com","user_status":"active"}
]
}
Update profile
- Method: PUT
- URL:
https://{company}.namely.com/api/v1/profiles/{id} - Watch out for: Namely uses PUT (not PATCH) for updates; only fields included in the body are changed. Omitted fields are not cleared.
Request example
PUT /api/v1/profiles/def456
Authorization: Bearer {access_token}
Content-Type: application/json
{"profiles":[{"job_title":"Senior Engineer"}]}
Response example
{
"profiles": [
{"id":"def456","job_title":"Senior Engineer","updated_at":"2024-06-15T10:00:00Z"}
]
}
Deactivate (terminate) profile
- Method: PUT
- URL:
https://{company}.namely.com/api/v1/profiles/{id} - Watch out for: There is no dedicated DELETE endpoint for profiles. Termination is performed by setting user_status to inactive and providing a departure_date.
Request example
PUT /api/v1/profiles/def456
Authorization: Bearer {access_token}
Content-Type: application/json
{"profiles":[{"user_status":"inactive","departure_date":"2024-06-30"}]}
Response example
{
"profiles": [
{"id":"def456","user_status":"inactive","departure_date":"2024-06-30"}
]
}
List groups
- Method: GET
- URL:
https://{company}.namely.com/api/v1/groups - Watch out for: Groups represent departments, teams, and other organizational units. Use group IDs when assigning profiles to departments.
Request example
GET /api/v1/groups?page=1&per_page=25
Authorization: Bearer {access_token}
Response example
{
"groups": [
{"id":"grp001","title":"Engineering","type":"department"}
]
}
Get current authenticated profile
- Method: GET
- URL:
https://{company}.namely.com/api/v1/profiles/me - Watch out for: Returns the profile of the token owner. Useful for validating token scope and identity.
Request example
GET /api/v1/profiles/me
Authorization: Bearer {access_token}
Response example
{
"profiles": [
{"id":"abc123","first_name":"Jane","email":"jane@acme.com"}
]
}
List events (audit/change log)
- Method: GET
- URL:
https://{company}.namely.com/api/v1/events - Watch out for: Events endpoint provides a changelog but is not a real-time webhook. Poll periodically for change detection if webhooks are not configured.
Request example
GET /api/v1/events?page=1&per_page=25
Authorization: Bearer {access_token}
Response example
{
"events": [
{"id":"evt001","type":"profile_updated","profile_id":"abc123","occurred_at":"2024-06-15T10:00:00Z"}
]
}
Rate limits, pagination, and events
- Rate limits: Namely enforces API rate limits but does not publicly document specific numeric thresholds in official docs as of the last known update.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: HTTP 429 is returned when limits are exceeded. Retry-After header presence is not confirmed in official docs. Implement exponential backoff on 429 responses.
- Pagination method: offset
- Default page size: 25
- Max page size: 50
- Pagination pointer: page and per_page
| Plan | Limit | Concurrent |
|---|---|---|
| All plans | Not publicly documented | 0 |
- Webhooks available: Yes
- Webhook notes: Namely supports webhooks that fire on HR events such as profile creation, updates, and terminations. Webhooks are configured in the Namely admin settings under Integrations.
- Alternative event strategy: Poll GET /api/v1/events or filter GET /api/v1/profiles by updated_at for change detection if webhooks are not available on your plan.
- Webhook events: profile.created, profile.updated, profile.terminated, profile.rehired
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Unknown; SSO prerequisite required (Okta or Azure AD/Entra ID integration must be configured first)
Endpoint: https://{company}.namely.com/scim/v2
Supported operations: GET /Users, GET /Users/{id}, POST /Users, PUT /Users/{id}, PATCH /Users/{id}, DELETE /Users/{id}, GET /Groups, POST /Groups, PATCH /Groups/{id}
Limitations:
- SSO must be configured before SCIM provisioning can be enabled.
- SCIM token is generated from within the Namely admin SSO settings; it does not use the standard OAuth token.
- Group (department) provisioning support may be limited depending on IdP configuration.
- Namely SCIM maps to the profiles object; not all custom HR fields are exposed via SCIM.
- Pricing tier required for SCIM is not publicly documented; confirm with Namely account team.
Common scenarios
Provisioning a new hire requires a POST to /api/v1/profiles with the body wrapped in a profiles array: {"profiles":[{... }]}.
Required fields are first_name, last_name, email, start_date; missing any returns a 422. Department assignment uses the group id from /api/v1/groups - retrieve group IDs before provisioning if department mapping is part of your identity graph sync.
For full roster sync, GET /api/v1/profiles?page=1&per_page=50, capture meta.total, and iterate pages. There is no server-side user_status filter in query params per official documentation - filter client-side by user_status=active. Store updated_at per profile to enable delta sync on subsequent runs and avoid full re-fetches.
Termination via REST API is a PUT to /api/v1/profiles/{id} with user_status=inactive and departure_date. If SCIM is active with Okta or Entra ID, the IdP sends a PATCH /scim/v2/Users/{id} with active=false on deprovision, and downstream SSO sessions are revoked by the IdP. SCIM deprovision is only functional if SSO is configured and the SCIM integration is active; without it, termination must be performed via REST API or the Namely UI.
Provision a new employee on hire
- Authenticate via OAuth 2.0 or use a personal access token.
- POST to /api/v1/profiles with first_name, last_name, email, start_date, job_title, and department id.
- Capture the returned profile id for future updates.
- Optionally assign the profile to groups via the groups array in the same POST body.
Watch out for: The request body must wrap the profile in a profiles array: {"profiles":[{...}]}. A 422 is returned if required fields are missing.
Sync all active employees to an external directory
- GET /api/v1/profiles?page=1&per_page=50 and capture meta.total.
- Iterate pages using the page parameter until all records are retrieved.
- Filter results client-side by user_status=active.
- Store updated_at per profile to enable delta sync on subsequent runs.
Watch out for: Max page size is 50. For companies with hundreds of employees, expect many paginated requests. There is no server-side filter by user_status in the query params per official docs - filter client-side.
Terminate an employee and revoke access via SCIM
- Via REST API: PUT /api/v1/profiles/{id} with user_status=inactive and departure_date set to the termination date.
- Via SCIM (if configured with Okta/Entra): The IdP sends a PATCH /scim/v2/Users/{id} with active=false upon deprovisioning in the IdP.
- Confirm the profile shows user_status=inactive via GET /api/v1/profiles/{id}.
- Downstream SSO sessions are revoked by the IdP as part of the SCIM deprovision flow.
Watch out for: SCIM deprovision only works if SSO is configured and the SCIM integration is active. Without SCIM, termination must be performed manually via the REST API or Namely UI.
Why building this yourself is a trap
The most common integration failure point is token lifecycle management. Personal access tokens are convenient for server-to-server use but create a silent dependency on the generating user's active status - deactivating that user breaks all integrations using their token with no advance warning.
OAuth tokens avoid this but require implementing refresh_token rotation; teams that skip rotation will encounter silent auth failures as tokens expire.
SCIM provisioning uses a separate bearer token generated in the SSO admin settings - it is entirely distinct from OAuth tokens and must be managed independently.
SCIM also requires SSO to be configured first, and not all custom HR fields are exposed via the SCIM schema, which limits identity graph fidelity for organizations relying on custom attributes.
For teams building against the Namely API as part of an identity graph with 60+ deep IT/identity integrations via an MCP server, the lack of a server-side user_status filter and the 50-record pagination cap are the primary throughput constraints at scale.
The events endpoint (/api/v1/events) provides a changelog for change detection but is not real-time; webhook configuration in Namely admin settings is the preferred path for event-driven workflows, supporting profile.created, profile.updated, profile.terminated, and profile.rehired events.
Automate Namely 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.