Custom HTTP Integration
Custom HTTP Integration
Custom HTTP lets you connect Scimify to applications that expose user and group management over REST (JSON, XML, or query-only), when there is no pre-built Scimify connector. You describe each SCIM operation as an HTTP request template; Scimify fills in values from the SCIM payload and parses the response so your identity provider still speaks standard SCIM to Scimify.
For applications that already implement SCIM 2.0, consider Scimify Proxy first—it forwards SCIM as-is and is simpler to configure.
Overview
- Your IdP SCIM goes to Scimify; Scimify translates each operation into configurable outbound HTTP calls to your API.
- You choose authentication: Bearer token, API key header, HTTP Basic, or OAuth 2.0 client credentials.
- You enable capabilities and define mappings: HTTP shape (method, URL, query, body, headers, success statuses) plus
response_fields—per-operation path maps so Scimify can read each downstream app’s JSON/XML shape into a normalized user or group record. - Preview (no network) and live test validate templates; optional sample response body on Preview checks
response_fieldswithout calling the API. Write operations can change real data—tests require explicit acknowledgment.
Prerequisites
- HTTPS endpoints reachable from Scimify (HTTP may be allowed only in non-production/debug configurations).
- API documentation (REST reference, OpenAPI/Swagger, or Postman collection) for create/update/delete/list users and groups as your app models them.
- Credentials or OAuth client for server-to-server access.
Authentication
Configure auth type in the integration; the secret is always stored in the encrypted api_token field (Bearer token, Basic password, API key value, or OAuth client secret).
| Auth type | Non-secret fields in auth | Secret |
|---|---|---|
bearer | — | Bearer token in api_token |
api_key_header | api_key_header_name (e.g. X-API-Key) | Header value in api_token |
basic | basic_username | Password in api_token |
oauth2_client_credentials | oauth_token_url, oauth_client_id, optional oauth_scope / oauth_audience | Client secret in api_token |
Example auth object (non-secret parts only—do not paste secrets into support tickets):
{ "type": "oauth2_client_credentials", "oauth_token_url": "https://id.example.com/oauth/token", "oauth_client_id": "YOUR_CLIENT_ID", "oauth_scope": "users.write groups.read"}Capabilities
Capabilities are booleans that declare which Scimify operations may run against your API. Use the exact keys below.
Supported capability keys
{ "create_user": true, "get_user": false, "update_user": true, "delete_user": false, "list_users": false, "create_group": true, "get_group": false, "update_group_members": true, "update_group_name": true, "delete_group": true, "list_groups": true}Validation rules (when you save an enabled instance)
- For each capability set to
true, you must define a non-emptymappingsentry with the same operation name (e.g.create_group: truerequires acreate_groupmapping). - Each of those mappings must include a non-empty
response_fieldsobject when the operation parses a success body, using only the keys allowed for that operation (see Response fields).delete_user,delete_group, andupdate_group_membersmust not defineresponse_fields(or leave it empty). - Turn off capabilities you are not using so you are not required to supply mappings for them. For example, only
create_groupenabled means only acreate_groupmapping is required—notupdate_group_members,update_group_name, ordelete_group. update_group_namehandles IdP-driven group renames (SCIM PATCH/PUT changingdisplayName). Enable it only if your IdP may rename groups and your API exposes a matching rename endpoint. It uses the same placeholders as group create:group_id(existing id in your app) andgroup_name(the new display name).update_usercovers PATCH deactivation from the IdP as well as profile updates; enable it only if your IdP will PATCH users and you have a matching HTTP mapping.- If
list_users/list_groupsare off, Scimify uses safe defaults where applicable (e.g. empty lists for discovery in some flows).
Example: users only (minimal)
Configure auth, enabled, and other instance fields in the Scimify admin UI. In the Capabilities (JSON) and Mappings (JSON) editors, use shapes like the following (every capability you set to true needs a matching entry under mappings).
capabilities — users only, create + update:
{ "create_user": true, "get_user": false, "update_user": true, "delete_user": false, "list_users": false, "create_group": false, "get_group": false, "update_group_members": false, "update_group_name": false, "delete_group": false, "list_groups": false}mappings — minimal entries for create_user and update_user only (adjust URLs, bodies, and response_fields to your API):
{ "create_user": { "http_method": "POST", "url_template": "https://api.example.com/v1/users", "body_kind": "json", "body_template": "{\"email\":\"{scim_user_email}\",\"name\":\"{scim_user_display_name}\"}", "success_status": [201], "response_fields": { "id": "id" } }, "update_user": { "http_method": "PATCH", "url_template": "https://api.example.com/v1/users/{integration_user_id}", "body_kind": "json", "body_template": "{\"active\":{scim_user_active}}", "success_status": [200, 204], "response_fields": { "id": "id", "userName": "userName", "email": "email", "displayName": "displayName", "active": "active" } }}Mappings
Each enabled operation can have an entry under mappings with this shape:
| Field | Purpose |
|---|---|
http_method | GET, POST, PUT, PATCH, or DELETE |
url_template | URL with optional {placeholders} (Python str.format style—see table below) |
query_params | Optional object: param name → template string (same placeholder rules) |
body_kind | none, json, or xml (default treated as none if omitted) |
body_template | String template; for json, content should be valid JSON after substitution |
content_type | Optional override (e.g. application/xml) |
headers | Optional object of header templates |
success_status | Optional list of acceptable HTTP status codes (e.g. [200, 201, 204]) |
response_fields | Required for operations that parse a success body (see Response fields); omit or {} only for delete_user, delete_group, update_group_members |
error_message_path | Optional single path into error responses for clearer failures (same path rules as one response_fields value) |
Template placeholders
Only these names are allowed in url_template, query_params, headers, and body_template:
| Placeholder | Typical use |
|---|---|
scim_user_email | Primary email from SCIM user |
scim_user_username | SCIM userName |
scim_user_display_name | displayName |
scim_user_given_name, scim_user_family_name | Name parts |
scim_user_active | "true" or "false" |
scim_user_json | Full SCIM user as a compact JSON string (use inside a JSON body carefully—escape-aware) |
scim_patch_json | PATCH body / patch ops as JSON string |
integration_user_id | Your app’s user id stored in Scimify after create |
group_id | Group id in your app |
group_name, group_description | Group display name / description (group_name is the new name when mapping update_group_name) |
member_ids_json | JSON array string of member user ids |
member_ids_csv | Comma-separated member ids |
Use a single {placeholder} per occurrence, e.g. https://api.example.com/v1/users/{integration_user_id}.
Response fields
response_fields is an object: Scimify field name → path string. Paths are always written as full paths from the response document root (no shared prefix key). That way fields that live in different branches of the JSON tree (for example id under data and email elsewhere) each get an accurate path.
Path rules
- JSON responses: dot-separated keys from the root, e.g.
data.user.id,user.email. - XML responses: slash-separated local tag names from the root element, e.g.
user/id,user_group/name. Attributes on the last segment may use forms likeUser/@idwhere supported. List operations currently expect JSON arrays foritems; XML list responses are not normalized in this version.
User-shaped keys (create_user, get_user, update_user, and each element of list_users)
| Key | Meaning |
|---|---|
id | User id in the downstream system (required mapping for these operations) |
userName | Login / username |
email | |
displayName | Display name |
active | Active flag (booleans and common string/number forms are coerced) |
You may omit optional keys if your API does not return them; Scimify fills gaps where possible using fallbacks (for example SCIM email on create, or stored id on update_user when the API returns 204 with an empty body).
List users (list_users)
- Add
items: path from the root to the JSON array of user objects. - Use
"items": ""(empty string) when the entire response body is a JSON array. - All other user keys (
id,userName,email,displayName,active) are paths relative to each array element (not prefixed with theitemspath).
Group-shaped keys (create_group, get_group, update_group_name, and each element of list_groups)
| Key | Meaning |
|---|---|
id | Group id (required on these operations; create_group may fall back to the requested name if missing) |
name | Group name (get_group and list_groups require this mapping) |
displayName | Optional display name |
description | Optional |
slug | Optional |
member_count | Optional (integer-like) |
List groups (list_groups)
Same pattern as list users: required items (plus id and name per element paths). Empty items if the root is the array.
Operations without response_fields
Do not set response_fields (or use an empty object {}) for:
delete_userdelete_groupupdate_group_members
Saving will reject non-empty response_fields on these operations.
Example: downstream JSON with different field names
If the API returns name for login and full_name for display:
"response_fields": { "id": "id", "userName": "name", "email": "email", "displayName": "full_name", "active": "enabled"}Example: full mappings (illustrative)
The following is illustrative—replace URLs, bodies, and paths with what your vendor API actually returns.
{ "create_user": { "http_method": "POST", "url_template": "https://api.example.com/v1/users", "body_kind": "json", "body_template": "{\"email\":\"{scim_user_email}\",\"name\":\"{scim_user_display_name}\",\"active\":{scim_user_active}}", "success_status": [200, 201], "response_fields": { "id": "id", "userName": "userName", "email": "email", "displayName": "displayName" } }, "update_user": { "http_method": "PATCH", "url_template": "https://api.example.com/v1/users/{integration_user_id}", "body_kind": "json", "body_template": "{\"active\":{scim_user_active},\"displayName\":\"{scim_user_display_name}\"}", "success_status": [200, 204], "response_fields": { "id": "id", "userName": "userName", "email": "email", "displayName": "displayName", "active": "active" } }, "list_users": { "http_method": "GET", "url_template": "https://api.example.com/v1/users", "query_params": { "pageSize": "200" }, "body_kind": "none", "success_status": [200], "response_fields": { "items": "items", "id": "id", "userName": "userName", "email": "email", "displayName": "displayName" } }, "create_group": { "http_method": "POST", "url_template": "https://api.example.com/v1/groups", "body_kind": "json", "body_template": "{\"name\":\"{group_name}\",\"description\":\"{group_description}\"}", "success_status": [201], "response_fields": { "id": "id", "name": "name", "displayName": "displayName" } }, "update_group_members": { "http_method": "PUT", "url_template": "https://api.example.com/v1/groups/{group_id}/members", "body_kind": "json", "body_template": "{\"userIds\":{member_ids_json}}", "success_status": [200, 204] }, "update_group_name": { "http_method": "PATCH", "url_template": "https://api.example.com/v1/groups/{group_id}", "body_kind": "json", "body_template": "{\"name\":\"{group_name}\"}", "success_status": [200, 204], "response_fields": { "id": "id", "name": "name", "displayName": "displayName" } }, "delete_group": { "http_method": "DELETE", "url_template": "https://api.example.com/v1/groups/{group_id}", "body_kind": "none", "success_status": [200, 204, 404] }, "list_groups": { "http_method": "GET", "url_template": "https://api.example.com/v1/groups", "body_kind": "none", "success_status": [200], "response_fields": { "items": "groups", "id": "id", "name": "name", "displayName": "displayName" } }}Query-only GET example
If the API uses query parameters only:
{ "get_user": { "http_method": "GET", "url_template": "https://api.example.com/v1/users/detail", "query_params": { "email": "{scim_user_email}" }, "body_kind": "none", "success_status": [200], "response_fields": { "id": "user.id", "userName": "user.userName", "email": "user.email", "displayName": "user.displayName", "active": "user.active" } }}XML body example (create_group)
Some APIs expect XML request bodies. Set body_kind to xml, optionally set content_type (e.g. text/xml), and put your XML skeleton in body_template using the same {placeholders} as JSON.
This example shows a generic POST that creates a group resource and expects HTTP 201. Element names and nesting follow your vendor’s spec—replace them with what your API documentation requires. Membership is often applied in a separate update_group_members mapping.
{ "create_group": { "http_method": "POST", "url_template": "https://api.example.com/v1/groups", "body_kind": "xml", "content_type": "text/xml", "body_template": "<group><name>{group_name}</name><description>{group_description}</description></group>", "success_status": [201], "response_fields": { "id": "group/id", "name": "group/name", "displayName": "group/name" } }}Configure authentication in the admin UI (e.g. Basic or Bearer) per your API. Set response_fields paths to match the XML success body (slash paths from the document root). If your tags differ, adjust segment names accordingly.
Preview and live test sample data (admin UI)
In the Scimify admin Integrations page, each Custom HTTP instance includes Preview (no outbound request) and live test actions. You can optionally supply Preview / live test context as a JSON object in the textarea, and a sample response body to verify response_fields:
- Leave context empty — Scimify uses built-in default samples for the operation you selected in the dropdown (placeholder emails, ids, group names, etc.).
- Provide context JSON — values are merged on top of those defaults so you can point tests at sandbox resources and avoid clashes with production.
- Sample response body (Preview only) — paste a representative success JSON or XML body; the Preview response includes
resolved_response, the user or group object (or list) Scimify would derive from yourresponse_fields. Content type is inferred (application/xmlif the pasted text looks like XML).
Merge behavior
scim_user— Object merged shallowly with the default SCIM-like user object for that operation (overrideuserName,emails,displayName, etc.).scim_patch— Merged with the default patch object when relevant (e.g.update_user).member_ids— Replaces the default list when provided (array of strings or numbers; used as strings in templates).integration_user_id,group_id,group_name,group_description— Override the built-in placeholder ids and names when present.
Unknown keys are ignored. Invalid JSON prevents Preview/Test from running until fixed.
Example: sandbox ids for live tests
{ "integration_user_id": "1938", "group_id": "42", "group_name": "SCIM-Sandbox-Engineering", "member_ids": ["1938", "1939"]}Example: custom email / userName only
{ "scim_user": { "displayName": "Sandbox User", }}Use Preview first to verify URLs and bodies; use live tests with care (mutating HTTP methods require an explicit acknowledgment in the UI).
How to build mappings from your application’s API docs
Use your vendor’s REST or OpenAPI documentation as a checklist—one SCIM lifecycle step at a time.
-
List the IdP-driven events you need
At minimum: user create, user update (including deactivate via PATCH), and offboarding (deactivate-only vs. true delete). For groups: create, replace membership, rename (if the IdP may change group display names), delete—and optionally list for discovery. -
For each capability, find the vendor endpoint
In the API reference, locate the operation that creates a user, updates a user by id, lists or searches users, and the same for groups/membership—including rename group if you enableupdate_group_name. Note method, path, required query parameters, and request body schema. -
Build
url_template
Copy the documented path. Replace path segments that vary per call with placeholders—e.g.{integration_user_id}or{group_id}where the doc shows a user or group identifier. -
Build
query_params
If the doc shows required or optional query fields (pagination,email=, etc.), add matching keys with template values so Scimify can substitute IdP-driven data. -
Choose
body_kind- Doc says JSON request body →
jsonand abody_templatewhose shape matches the documented schema (properties may map fromscim_user_*placeholders). - Doc says XML →
xml, setcontent_typeif needed, and put the XML skeleton inbody_template. - GET/DELETE with no body →
none(omitbody_templateor leave it empty).
- Doc says JSON request body →
-
Set
success_status
From the doc’s “Responses” section, list every status that means success for that call (often200,201,204). -
Set
response_fieldsfrom an example
Paste the documented example success response (or use Preview’s sample response body). For each Scimify field your operation needs (id,email, …), add a path string from the document root (Response fields).- Single resource (
get_user,create_user, …): map user or group keys with full dot or slash paths. - Lists (
list_users,list_groups): setitemsto the path of the JSON array; mapid,name, etc. relative to one element of that array. Use"items": ""if the response root is the array. - XML: slash paths from the root element.
- Deletes /
update_group_members: omitresponse_fields.
- Single resource (
-
Align deactivation and delete
If the IdP sends PATCH withactive: falsebut your API deletes the user, map that underupdate_useror usedelete_userif you truly issue SCIM DELETE—match what your IdP sends. Optional: use Scimify’s “deactivation treated as downstream delete” flag if your downstream removes the account on what SCIM considers deactivation. -
Validate with Preview, then read-only live tests
Use Preview in the Scimify admin UI to confirm expanded URL, query string, and body. Run live tests starting with GET/list operations; mutating tests require an explicit side-effect acknowledgment. -
OAuth
If the doc specifies client credentials, configureoauth2_client_credentialsand use OAuth token only test mode before hitting resource endpoints.
Copying settings between instances
You can create a new Custom HTTP instance and copy non-secret settings from an existing instance in the same tenant (mappings, capabilities, auth metadata). You must supply new secrets and a new IdP-facing SCIM API key through the normal flows.
Security notes
- Prefer HTTPS for all token and resource URLs.
- Do not put secrets inside URL templates or bodies where logs or previews could expose them; use the dedicated secret field.
- Live tests against production can create, update, or delete real data—use sandbox credentials when possible.
Related
- Scimify overview
- Okta SCIM configuration
- Scimify Proxy (downstream speaks SCIM)
Support
If you need help translating a specific vendor API into mappings, contact Veraproof support with redacted request/response examples (no tokens or passwords).