Skip to content

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_fields without 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 typeNon-secret fields in authSecret
bearerBearer token in api_token
api_key_headerapi_key_header_name (e.g. X-API-Key)Header value in api_token
basicbasic_usernamePassword in api_token
oauth2_client_credentialsoauth_token_url, oauth_client_id, optional oauth_scope / oauth_audienceClient 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-empty mappings entry with the same operation name (e.g. create_group: true requires a create_group mapping).
  • Each of those mappings must include a non-empty response_fields object when the operation parses a success body, using only the keys allowed for that operation (see Response fields). delete_user, delete_group, and update_group_members must not define response_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_group enabled means only a create_group mapping is required—not update_group_members, update_group_name, or delete_group.
  • update_group_name handles IdP-driven group renames (SCIM PATCH/PUT changing displayName). 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) and group_name (the new display name).
  • update_user covers 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_groups are 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:

FieldPurpose
http_methodGET, POST, PUT, PATCH, or DELETE
url_templateURL with optional {placeholders} (Python str.format style—see table below)
query_paramsOptional object: param name → template string (same placeholder rules)
body_kindnone, json, or xml (default treated as none if omitted)
body_templateString template; for json, content should be valid JSON after substitution
content_typeOptional override (e.g. application/xml)
headersOptional object of header templates
success_statusOptional list of acceptable HTTP status codes (e.g. [200, 201, 204])
response_fieldsRequired for operations that parse a success body (see Response fields); omit or {} only for delete_user, delete_group, update_group_members
error_message_pathOptional 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:

PlaceholderTypical use
scim_user_emailPrimary email from SCIM user
scim_user_usernameSCIM userName
scim_user_display_namedisplayName
scim_user_given_name, scim_user_family_nameName parts
scim_user_active"true" or "false"
scim_user_jsonFull SCIM user as a compact JSON string (use inside a JSON body carefully—escape-aware)
scim_patch_jsonPATCH body / patch ops as JSON string
integration_user_idYour app’s user id stored in Scimify after create
group_idGroup id in your app
group_name, group_descriptionGroup display name / description (group_name is the new name when mapping update_group_name)
member_ids_jsonJSON array string of member user ids
member_ids_csvComma-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 like User/@id where supported. List operations currently expect JSON arrays for items; XML list responses are not normalized in this version.

User-shaped keys (create_user, get_user, update_user, and each element of list_users)

KeyMeaning
idUser id in the downstream system (required mapping for these operations)
userNameLogin / username
emailEmail
displayNameDisplay name
activeActive 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 the items path).

Group-shaped keys (create_group, get_group, update_group_name, and each element of list_groups)

KeyMeaning
idGroup id (required on these operations; create_group may fall back to the requested name if missing)
nameGroup name (get_group and list_groups require this mapping)
displayNameOptional display name
descriptionOptional
slugOptional
member_countOptional (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_user
  • delete_group
  • update_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 your response_fields. Content type is inferred (application/xml if the pasted text looks like XML).

Merge behavior

  • scim_user — Object merged shallowly with the default SCIM-like user object for that operation (override userName, 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": {
"userName": "[email protected]",
"displayName": "Sandbox User",
"emails": [{ "value": "[email protected]", "primary": true }]
}
}

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.

  1. 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.

  2. 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 enable update_group_name. Note method, path, required query parameters, and request body schema.

  3. 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.

  4. 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.

  5. Choose body_kind

    • Doc says JSON request body → json and a body_template whose shape matches the documented schema (properties may map from scim_user_* placeholders).
    • Doc says XML → xml, set content_type if needed, and put the XML skeleton in body_template.
    • GET/DELETE with no body → none (omit body_template or leave it empty).
  6. Set success_status
    From the doc’s “Responses” section, list every status that means success for that call (often 200, 201, 204).

  7. Set response_fields from 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): set items to the path of the JSON array; map id, 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: omit response_fields.
  8. Align deactivation and delete
    If the IdP sends PATCH with active: false but your API deletes the user, map that under update_user or use delete_user if 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.

  9. 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.

  10. OAuth
    If the doc specifies client credentials, configure oauth2_client_credentials and 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.

Support

If you need help translating a specific vendor API into mappings, contact Veraproof support with redacted request/response examples (no tokens or passwords).