HappySignals SCIM API Reference
Reference documentation for the HappySignals SCIM 2.0 API
For a step-by-step guide to configuring Microsoft Entra ID provisioning against this API, see the Set up SCIM user sync with HappySignals article.
The API implements SCIM 2.0 as defined in RFC 7643 and RFC 7644.
Base URL
https://<tenant>.<environment>.happysignals.com/scim/v2/
Environments include e.g. emea, us, uk. Your exact base URL is confirmed by HappySignals support during onboarding.
Authentication
The API uses the OAuth 2.0 client credentials grant (RFC 6749 §4.4). Microsoft Entra ID handles this exchange transparently when configured via the gallery integration; this section documents the underlying flow for programmatic callers.
Token endpoint
POST https://<tenant>.<environment>.happysignals.com/oauth/token/ Content-Type: application/x-www-form-urlencoded
Request parameters:
| Parameter | Value |
|---|---|
grant_type |
client_credentials |
client_id |
Client ID issued by HappySignals support |
client_secret |
Client Secret issued by HappySignals support |
Successful response (HTTP 200):
{ "access_token": "<JWT>", "token_type": "Bearer", "expires_in": 900 }
The access_token is a JWT signed with HS256. It carries the standard claims iss, sub, aud, iat, exp, jti, and client_id. iss and aud both resolve to your tenant's primary domain.
Access tokens expire after 15 minutes. No refresh tokens are issued — obtain a new access token by re-running the client credentials exchange.
Using the access token
Send the access token as a bearer token on every SCIM request:
Authorization: Bearer <access_token>
Token endpoint errors
| HTTP status | error value |
Cause |
|---|---|---|
| 400 | invalid_request |
Missing grant_type, client_id, or client_secret. |
| 400 | unsupported_grant_type |
grant_type was not client_credentials. |
| 401 | invalid_client |
Unknown client, wrong secret, or client is deactivated. |
| 415 | — | Content-Type was not application/x-www-form-urlencoded. |
Supported user attributes
SCIM User resources use the core schema plus three extensions. Send the extension URNs in the schemas array alongside the core User schema when writing extension attributes.
| Attribute | Schema URN | Type | Required | Mutability | Notes |
|---|---|---|---|---|---|
id |
core | string | — | readOnly | Server-assigned. Immutable. |
userName |
core | string | yes | readWrite | Unique per tenant. |
externalId |
core | string | no | readWrite | Client-owned identifier (e.g. Entra objectId). |
active |
core | boolean | no | readWrite | false deactivates without deleting. |
name.givenName |
core | string | no | readWrite | |
name.familyName |
core | string | no | readWrite | |
endUserIdSource |
urn:ietf:params:scim:schemas:extension:happysignals:identifiers:2.0:User |
string | no | writeOnly | Never returned. Required to write Enterprise or Organization attributes for a user that does not yet have an established internal identifier. |
upn |
urn:ietf:params:scim:schemas:extension:happysignals:identifiers:2.0:User |
string | no | readWrite | User Principal Name. |
email |
urn:ietf:params:scim:schemas:extension:happysignals:identifiers:2.0:User |
string | no | readWrite | |
objectId |
urn:ietf:params:scim:schemas:extension:happysignals:identifiers:2.0:User |
string | no | readWrite | |
organization |
urn:ietf:params:scim:schemas:extension:enterprise:2.0:User |
string | no | readWrite | |
division |
urn:ietf:params:scim:schemas:extension:enterprise:2.0:User |
string | no | readWrite | |
department |
urn:ietf:params:scim:schemas:extension:enterprise:2.0:User |
string | no | readWrite | |
country |
urn:ietf:params:scim:schemas:extension:happysignals:organization:2.0:User |
string | no | readWrite | Normalised and also stored as the response country in HappySignals reporting. |
jobRole |
urn:ietf:params:scim:schemas:extension:happysignals:organization:2.0:User |
string | no | readWrite | |
employmentType |
urn:ietf:params:scim:schemas:extension:happysignals:organization:2.0:User |
string | no | readWrite | canonicalValues are advisory — any string is accepted. |
employmentStartDate |
urn:ietf:params:scim:schemas:extension:happysignals:organization:2.0:User |
string | no | readWrite | Must parse as ISO 8601. Invalid values return 400 invalidValue. |
Discovery endpoints (/Schemas, /ResourceTypes, /ServiceProviderConfig) return the authoritative machine-readable schema.
Endpoints
All endpoints are relative to the base URL.
Discovery
| Method | Path | Description |
|---|---|---|
| GET | /ServiceProviderConfig |
Feature support (patch, filter, bulk, etc.). |
| GET | /Schemas |
List all supported schemas. |
| GET | /Schemas/{id} |
Retrieve a specific schema by URN. |
| GET | /ResourceTypes |
List supported resource types (Users only). |
| GET | /ResourceTypes/{id} |
Retrieve a specific resource type. |
Users
| Method | Path | Description |
|---|---|---|
| GET | /Users |
List or filter users. Returns a ListResponse. |
| POST | /Users |
Create a user. Returns HTTP 201 with the created resource. |
| GET | /Users/{id} |
Retrieve a user by SCIM id. |
| PUT | /Users/{id} |
Replace a user (full-object update). |
| PATCH | /Users/{id} |
Modify a user via a SCIM PatchOp payload. |
| DELETE | /Users/{id} |
Permanently delete a user. Returns HTTP 204. |
Filtering and pagination
GET /Users accepts filter, startIndex, and count.
Filter grammar. Only the eq operator on userName or externalId is supported:
GET /Users?filter=userName eq "alice@acme.com" GET /Users?filter=externalId eq "aaaabbbb-0000-cccc-1111-dddd2222eeee"
Any other operator, attribute, or combination returns 400 invalidFilter.
Pagination.
startIndexis 1-based. Defaults to 1.countdefaults to 100 and is capped at 100.- Sort order is stable but not client-controllable. No
sortBy/sortOrderparameters are supported.
Responses follow the SCIM ListResponse shape:
{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"], "totalResults": 42, "startIndex": 1, "itemsPerPage": 20, "Resources": [ ... ] }
Behaviour notes
DELETE is destructive.
DELETE /Users/{id}permanently removes the identity from HappySignals. For reversible deprovisioning (the pattern Microsoft Entra ID and most IdPs use), sendPATCHwithactiveset tofalseinstead.
PATCH is lenient.
Unrecognised operations, paths, or attributes are silently skipped. The request only fails with 400 if no operation could be applied.
PATCH filter paths are not supported.
Expressions likeemails[type eq "work"].valuein a PATCHpathreturn 400invalidPath. Send the enclosing attribute as an object instead.
Not supported: /Groups, /Bulk, /Me, sort, ETag (If-Match), password change (changePassword).
Errors
All errors use the standard SCIM error envelope:
{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "status": "400", "detail": "Human-readable description", "scimType": "invalidValue" }
scimType values
scimType |
HTTP | Meaning |
|---|---|---|
invalidFilter |
400 | Filter grammar not supported (see Filtering and pagination). |
invalidValue |
400 | An attribute value failed validation (e.g. non-ISO 8601 employmentStartDate, or Enterprise / Organization attributes sent without a resolvable endUserIdSource). |
invalidPath |
400 | PATCH path is malformed or uses an unsupported expression. |
mutability |
400 | Tried to write a readOnly attribute, or change an immutable value. |
uniqueness |
409 | A resource with the same userName already exists. |
noTarget |
400 | PATCH remove targeted an attribute that does not exist on the resource. |
OAuth-layer errors reaching SCIM endpoints
If the bearer token fails validation, the SCIM endpoint returns HTTP 401 with one of the following detail strings:
Token has expired.— request a new access token.Invalid token audience./Invalid token issuer.— the token was issued for a different HappySignals tenant.Client not found.— the OAuth client has been deactivated. Contact support.
End-to-end example
Provision, retrieve, update, and deactivate a user against the tenant acme.emea.happysignals.com.
1. Obtain an access token
curl -X POST https://acme.emea.happysignals.com/oauth/token/ \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=cli_abc123" \ -d "client_secret=sec_xxxxxxxx"
Response:
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 900 }
2. Create a user
curl -X POST https://acme.emea.happysignals.com/scim/v2/Users \ -H "Authorization: Bearer eyJhbGciOi..." \ -H "Content-Type: application/scim+json" \ -d '{ "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" ], "userName": "alice@acme.com", "externalId": "aaaabbbb-0000-cccc-1111-dddd2222eeee", "active": true, "name": { "givenName": "Alice", "familyName": "Example" }, "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { "department": "Engineering", "organization": "Acme Corp" } }'
Response (HTTP 201) includes the assigned id, e.g. "id": "1234".
3. Retrieve the user
curl https://acme.emea.happysignals.com/scim/v2/Users/1234 \ -H "Authorization: Bearer eyJhbGciOi..."
4. Deactivate the user
curl -X PATCH https://acme.emea.happysignals.com/scim/v2/Users/1234 \ -H "Authorization: Bearer eyJhbGciOi..." \ -H "Content-Type: application/scim+json" \ -d '{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "replace", "path": "active", "value": false } ] }'
Response: HTTP 200 with the updated resource. The user is retained in HappySignals but marked inactive. To permanently delete instead, use DELETE /Users/1234.