ServiceNow IntegrationHub | Entitle
BeyondTrust Entitle for ServiceNow lets your users request just-in-time (JIT) access to applications, systems, and other resources governed by Entitle, directly from the ServiceNow Service Catalog. Each request goes through your configured approval process. Entitle fulfills it, and ServiceNow tracks it to completion. When the approved duration expires, Entitle revokes access automatically, so no manual cleanup is required.
This guide refers to the Entitle Spoke, or simply the Spoke. A spoke is a ServiceNow IntegrationHub component that packages actions for connecting to a third-party system. The Entitle Spoke handles all API calls between ServiceNow and Entitle. It is installed alongside the main application but does not require further interaction after setup.
Key features
- Native catalog experience: A ready-to-use Request Entitle Access catalog item offers each user only the resources they are eligible for in Entitle. You can narrow it to bundles only or roles only.
- Eligibility caching: The app caches each user's eligibility and refreshes it automatically, so the request form loads quickly while staying close to current. Entitle still checks eligibility at submission.
- Configurable approvals: A built-in approval chain routes each request to the manager or a default group, with optional Change Advisory Board (CAB) escalation for long durations. You can replace it entirely with your own approval logic.
- Time-limited access: Durations come from each resource's settings in Entitle or from your configured fallback list. Entitle revokes access automatically when the duration expires.
- Status reconciliation: Push updates from Entitle's webhook, which is enabled by default, drive every request to closure and keep requesters informed. An optional polling fallback is also available.
- Extension hooks: Four override points let you change the application's behavior without modifying it. Three customize individual steps (approval, pre-submit validation, and notifications), and one replaces the entire fulfillment flow.
Architecture
The integration consists of two scoped applications:
| Application | Scope | Purpose |
|---|---|---|
| BeyondTrust Entitle Spoke | x_bets_entitle_spo | Client for the Entitle API. It contains six IntegrationHub actions built on native Representational State Transfer (REST) steps, the Entitle - Get User Eligibility (All Pages) subflow, an EntitleError normalizer for API failures, and a single Connection & Credential Alias. It contains no business logic, no tables, and no configuration of its own. |
| BeyondTrust Entitle | x_bets_entitle | Everything else: the catalog item, eligibility caching, the fulfillment flow, approvals, status reconciliation, configuration, and the customization hooks. Status reconciliation uses the webhook by default, with optional polling. |
The main application does all its Entitle communication through the Spoke and cannot function without it.
Request workflow
- A user with the
x_bets_entitle.requesterrole opens Request Entitle Access in the catalog and picks a resource they are eligible for, a duration, and a justification. - The Access Request flow validates the request and runs approval, using either the built-in chain or your custom Approval Hook. It then runs pre-submit validation and submits the request to Entitle through the Spoke.
- ServiceNow tracks the Entitle request to a terminal state, normally through Entitle's push webhook, or through the optional polling flow if you have activated it. ServiceNow then closes the requested item (RITM) and notifies the requester.
- Entitle provisions the access and automatically revokes it when the duration expires.
Prerequisites
Ensure you have:
BeyondTrust Entitle
- An Entitle tenant, and an Entitle administrator account that can manage Org settings, where you create an API token in Step 2
- Your tenant's regional API base URL:
- Global:
https://api.entitle.io/public/v1 - US:
https://api.us.entitle.io/public/v1 - Canada:
https://api.ca.entitle.io/public/v1
- Global:
ServiceNow
- A ServiceNow instance on a supported release: Zurich or later
- Flow Designer and IntegrationHub available, through the
com.glide.hub.integrationplugin - Rights to install applications and administer Connections & Credentials
- Outbound network access from the instance to the Entitle API host for your region
ImportantThe Spoke is a prerequisite of the main application and must be installed first. The main application declares the minimum Spoke version it needs, and the platform enforces it at install time.
Initial setup
Step 1: Install the applications (ServiceNow)
- In ServiceNow, go to All > System Applications > All Available Applications > All.
- Install BeyondTrust Entitle Spoke (
x_bets_entitle_spo) first. - Install BeyondTrust Entitle (
x_bets_entitle) second. The app declares a dependency on the Spoke, including its minimum version. If you install in the wrong order, or over a Spoke that is too old, the dependency check fails.
When you install the main app, it automatically:
- Seeds the single Entitle Configuration record, named
Default, with opt-in defaults: no duration options selected, Log Level set toError, and Webhook Enabled set totrue. For every value, see the Configuration reference. - Creates the Request Entitle Access catalog item in a BeyondTrust Entitle category within the standard Service Catalog.
- Creates the BeyondTrust Entitle navigation menu, visible to
x_bets_entitle.admin, with four modules: Configuration, Requests, Help, and App Privacy Policy. - Activates one recurring job: the daily Purge Expired Entitle Eligibility cleanup job. The app also installs the optional Status Reconciliation polling flow but leaves it inactive. For more information, see Enable status polling.
Nothing tenant-specific ships with the app. You set the Entitle connection URL and API token, the webhook service account, approval groups, duration options, and hook references in the steps that follow.
Step 2: Create the Entitle API token (Entitle)
- Sign in to Entitle as an administrator and open Org settings.
- Open the Tokens tab and click Add. Choose an API token, not an Agent token.
- Enter a Token name that identifies its use, for example
ServiceNow integration. The name must be 2–250 characters. - Select an Expiration that matches your credential policy, and record the date. The integration stops working when the token expires. For more information see Credential rotation.
- Click Reveal token, copy the value, and store it in your secrets manager. Entitle shows the value only at creation time. If you lose it, Revoke the token in the same list and create a new one.
The Spoke authenticates to Entitle with this API token. It is an organization-level credential that is not tied to any user, so it keeps working when individual administrators leave. Do not use a personal access token for the integration. Personal access tokens are bound to the user who created them and are meant for that user's own API access.
ImportantThe API token carries administrator rights across your Entitle organization. Treat it as a privileged secret. Store it only in your secrets manager and in the ServiceNow credential record you create in the next step, which encrypts it. Never store it in scripts, tickets, or chat.
Step 3: Connect ServiceNow to your Entitle tenant (ServiceNow)
-
In ServiceNow, go to All > Connections & Credentials > Credentials.
-
Click New, and choose API Key Credentials.
-
Give it a name, for example
Entitle API Key. -
Paste the API token from Step 2 into the API Key field.
-
Click Submit. ServiceNow encrypts the value on save and sends it as a
Bearertoken on every call. -
Go to All > Connections & Credentials > Connection & Credential Aliases and open EntitleConnectionAlias (
x_bets_entitle_spo.EntitleConnectionAlias). -
In its Connections related list, click New and create an HTTP(s) Connection.
-
Give it a name, for example
Entitle API. -
Set Credential to the credential from step 1, and set Connection URL to your regional Entitle API base URL, listed in Prerequisites.
-
Click Submit.
-
Verify the connection. Go to All > System Definition > Scripts - Background, leave the scope set to global, and run:
var out = sn_fd.FlowAPI.getRunner() .action('x_bets_entitle_spo.entitle__list_bundles') .inForeground() .withInputs({ limit: 5 }) .run() .getOutputs(); gs.info(out.result_json);A result with
"ok": trueand bundle data confirms connectivity and credentials. A result with"ok": falseand"code": "auth_error"means Entitle rejected the token.
The Spoke:
- Reads the Entitle base URL and API token through a single Connection & Credential Alias, EntitleConnectionAlias.
- Installs the alias with nothing attached, which is why you create the credential and connection yourself.
- Publishes its actions for cross-scope use, so the verification script can call them from the global scope. Use the global scope, because Scripts - Background does not offer the scopes of applications installed from the ServiceNow Store or a company application repository.
- Has no script-include client; its actions and subflow are its only surface.
The internal action name
x_bets_entitle_spo.entitle__list_bundlescontains a double underscore.
Step 4: Assign roles (ServiceNow)
- In ServiceNow, go to All > User Administration > Users or Groups.
- Grant
x_bets_entitle.adminto the people who will administer the integration. - Grant
x_bets_entitle.requesterorx_bets_entitle.proxy_requesterto the users who may request access. A group is usually the easiest way to grant these roles. - Do not assign
x_bets_entitle.apihere. It belongs only to the webhook service account you create in Step 6.
The app defines four roles:
| Role | Assign to | Purpose |
|---|---|---|
x_bets_entitle.admin | Integration administrators | Full administrative access: the navigation menu, the Configuration record, and all app data tables. |
x_bets_entitle.requester | Users who may request access | Makes the catalog category and the Request Entitle Access item visible. The Entitle Requesters user criteria on this role gates the item. |
x_bets_entitle.proxy_requester | Delegates and coordinators | Contains the requester role, so it grants everything requester grants. It also adds the On Behalf Of field to the request form, for submitting on another user's behalf. |
x_bets_entitle.api | Only the webhook service account | Grants nothing except permission to call the inbound events endpoint. Do not assign it to people. |
Step 5: Configure approvals and durations (ServiceNow)
-
In ServiceNow, go to BeyondTrust Entitle > Configuration. This opens the classic UI16 or Polaris form.
The form opens directly on the single
Defaultrecord. Use its Save button to stay on the form. -
In the Approvals section of the main form, set a Default Approval Group. The built-in approval chain uses it whenever a requester has no manager. If neither a manager nor a default group is available, the chain rejects the request outright.
-
On the Request Durations tab, use the checkbox picker to select at least one fallback duration option. The request form offers these when an Entitle resource doesn't define its own allowed durations. The app ships with none selected, and no one can submit a request until you select at least one. Optionally, set a Default Duration from among them.
-
Click Save.
-
(Optional) To require a second approval for long-duration requests, go to the CAB escalation section of the main form and set a CAB Approval Group and a CAB Escalation Duration (Days). See The built-in approval chain.
-
(Optional) In the Offered Resource Types field on the main form, leave the default of Bundles and Roles, or narrow the request form to Bundles only or Roles only. This setting filters only what the form shows. The app still fetches and caches eligibility in full, and doesn't enforce the setting server-side; see the Configuration reference.
Leave Webhook Enabled on the Status Updates tab at its default of true. The webhook you connect in Steps 6 and 7 is how requests get closed.
ImportantKeep the duration selection in sync with Entitle's own settings. In the Entitle admin console, go to Administration > Org Settings > JIT Requests. Entitle doesn't expose these settings through its API, so the app can't synchronize them automatically.
The Configuration form's duration picker renders only in the classic UI16 or Polaris form. Administer this record from the classic UI, not Configurable Workspace.
Step 6: Create the webhook service account (ServiceNow)
The webhook is how requests get closed: Entitle pushes each status change to the app's inbound endpoint, authenticating as this account. Webhook Enabled is already true, but nothing arrives until you complete this step and Step 7. To poll Entitle for status instead of, or in addition to, the webhook, see Enable status polling.
- In ServiceNow, go to All > User Administration > Users.
- Go to User Administration > Users, and then click New.
- Configure the user:
- User ID:
entitle_webhook_user, or your preferred name - First name: Entitle
- Last name: Webhook User
- Identity Type:
Machine - Active: checked
- User ID:
- Click Submit, then reopen the user record and click Set Password. Record the password securely. You need it in the next step.
- On the Roles tab, click Edit and add exactly one role:
x_bets_entitle.api. Grant no other roles.
Step 7: Add the webhook (Entitle)
-
On your workstation, generate the Base64 value for the header from
<user>:<password>of the account you created in Step 6. Either command below encodes as UTF-8 with no trailing newline. Replace the two placeholders and copy the output:[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('entitle_webhook_user:YOUR_PASSWORD'))printf '%s' 'entitle_webhook_user:YOUR_PASSWORD' | base64 -
In Entitle, go to Org settings > Audit Logs Webhooks and add a webhook with these values:
- Endpoint URL:
https://<instance>.service-now.com/api/x_bets_entitle/entitle_events_api/v1/events - Header:
{"Authorization": "Basic <value from step 1>"}
- Endpoint URL:
-
Save the webhook.
ImportantIf you build the Base64 value another way, use UTF-8 with no trailing newline. PowerShell's default
Unicodeencoding and bashechowithout-nboth produce broken credentials; the commands in step 1 avoid both problems. A credential failure produces no application log entry, because platform authentication runs before the app's code. Every failed delivery also counts against Entitle's limit for automatically disabling the webhook, so verify the header value before you save the webhook.
Step 8: Smoke test (ServiceNow)
-
In ServiceNow, use Service Portal or Employee Center, and then go to BeyondTrust Entitle > Requests.
Complete these steps as a user who holds
x_bets_entitle.requester. Don't use an admin account, and don't impersonate another user. -
Open Request Entitle Access. The Resource list offers the resources that user is eligible for in Entitle, limited to the types that Offered Resource Types allows. The first load can take a few seconds while the app fetches eligibility.
-
Submit a request with a short duration and justification.
-
Approve it as the manager or as a member of the Default Approval Group.
-
Watch BeyondTrust Entitle > Requests. The tracking record reaches a terminal state, and the RITM closes with a status comment. With the webhook, this happens within seconds. With the polling flow, it happens on the next due poll.
If the RITM stays open after Entitle shows a decision, see RITM stays open long after Entitle shows a decision. Your basic installation is complete once this test closes the RITM.
Optional setup
Place and brand the catalog item (ServiceNow)
In ServiceNow, go to Service Catalog > Maintain Items > Request Entitle Access.
The item ships in the BeyondTrust Entitle category of the standard Service Catalog so users can find it immediately, but that is just its default home:
- Move or co-locate it anywhere. The preferred method is to add your own category through the item's Categories related list. That association lives in your scope and never marks the shipped record as customized. You can also edit the item's Category field directly. Routing is unaffected either way: fulfillment follows the item, not its location, so an Entitle item can sit on the same request page as items your own flows fulfill.
- Rebrand if desired. The item record is intentionally editable: you can rename it and change its short description, description, and icon. The form's fields, Resource, Duration, and Justification, are already brand-neutral.
Direct edits to the shipped item record mark it as customized, so upgrades stop applying vendor updates to that record. Review such records in your upgrade history after each app upgrade.
The item's request experience is designed for Service Portal and Employee Center. In the classic catalog UI, platform-level controls such as quantity, delivery time, and cart may still display. They have no effect on an access request.
Enable status polling (ServiceNow)
-
In ServiceNow, go to Flow Designer, also called Workflow Studio, and open Status Reconciliation in the BeyondTrust Entitle application.
Polling is an optional fallback alongside the webhook, or the only status path where your organization doesn't permit inbound webhooks. For how the two paths interact, see Status reconciliation.
-
Open Status Reconciliation and click Activate. This flow is the one shipped record that is not read-only, so that you can activate it. Don't change anything else in it.
-
(Optional) Adjust Polling Interval (minutes) and Maximum Polling Age (days) on the Configuration record's Status Updates tab. See Tune polling.
To stop polling, open the flow again and click Deactivate. When you activate the flow, the platform marks it as customized on your instance; see Upgrades.
Customize approvals, validation, or notifications
To replace the built-in approval chain, add pre-submit checks, or notify requesters through another channel (see Customize the application). For example, you can auto-approve in ServiceNow and let Entitle's own workflow approve.
The requester experience
Request Entitle Access presents four fields:
| Field | Behavior |
|---|---|
| Resource | Only resources the requesting user is currently eligible for in Entitle, limited to the types that the Configuration record's Offered Resource Types allows. The default is bundles and roles. The app caches eligibility per user and refreshes it automatically: in the background when the cache is mildly stale, and synchronously when it is expired or empty. |
| Duration | The allowed durations for the selected resource. If the resource defines its own allowed durations in Entitle, the form offers those. Otherwise, it uses the fallback list from the Configuration record. The form offers Forever only where it is enabled. |
| Justification | Mandatory free text that the app passes to Entitle and that approvers can see. |
| On Behalf Of | Visible only to holders of x_bets_entitle.proxy_requester. Submits the request for another user, whose manager and eligibility then drive approval and fulfillment. |
Notable guardrails:
- Impersonation is blocked. An impersonating admin sees a warning on the form and can't submit. A server-side rule enforces the same block regardless of client state.
- One request, one RITM. Each RITM maps to exactly one Entitle request, and the app enforces this server-side.
- Requesters receive one comment on their RITM when the request is submitted, and one when it closes. The first comment includes the resource, duration, and Entitle reference ID. The second includes the outcome and its reason. The fulfillment flow writes these comments itself. A notification hook can add other channels but doesn't replace them. If your instance's Request Item commented email notification is active, the platform also emails each comment to the requester.
Configuration reference
All application settings live on the single Entitle Configuration record, x_bets_entitle_configuration, named Default. The app deliberately ships no system properties. The record is a singleton, and the app blocks inserting a second row. The app seeds the record on install with the defaults below. Changes take effect immediately, with no cache flush or restart needed.
| Setting | Tab | Default | Description |
|---|---|---|---|
| Name | Main | Default | Fixed identifier of the singleton record. Read-only. |
| Offered Resource Types | Main | Bundles and Roles | Which resource types the request form's Resource list offers: Bundles and Roles, Bundles only, or Roles only. This is a display filter, not a control. The app still fetches and caches eligibility for every type, and a change applies on the next form load with no cache refresh. If a request for a hidden type arrives another way, such as through REST, an order guide, or a script, the app still accepts it when Entitle says the user is eligible. Entitle remains the authority on what a user may have. |
| Default Approval Group | Main | empty | Group that the built-in approval chain uses when the requester has no manager. The chain is fail-closed: with no manager and no group, it rejects requests. |
| CAB Approval Group | Main | empty | Group that approves CAB-escalated requests. Leave it empty to disable CAB escalation. |
| CAB Escalation Duration (Days) | Main | 0 | Requests for this many days or longer, or for Forever, require a second approval from the CAB group. 0 disables escalation. |
| Duration Options | Request Durations | None; select during setup | Fallback durations that the request form offers when the Entitle resource defines none of its own. You must select at least one before anyone can submit a request. You manage this setting through the checkbox picker, and the app stores it as comma-separated seconds, where -1 means Forever. |
| Default Duration | Request Durations | None | Pre-selected duration on the request form. Must be one of the enabled duration options; the form validates this on save. |
| Eligibility Soft TTL (minutes) | Eligibility Cache | 60 | Time to live (TTL): the age at which cached eligibility becomes stale. The app still serves stale eligibility but refreshes it in the background. |
| Eligibility Hard Expiry (minutes) | Eligibility Cache | 480 | Age at which cached eligibility becomes unusable. The app refreshes it synchronously before serving the form. |
| Polling Interval (minutes) | Status Updates | 5 | Minimum minutes between status polls for each in-flight request. Applies only after you activate the Status Reconciliation flow, which ships inactive. That flow runs every minute, and this field is the only setting you need to tune. |
| Maximum Polling Age (days) | Status Updates | 7 | How long polling keeps trying a submitted request that has not reached a final Entitle status. Once a request exceeds this age, the app sets it to failed and closes the RITM as Closed Incomplete with an explanatory comment. A blank value, or a value below 1, uses 7; there is no "never give up" setting. Applies only after you activate the Status Reconciliation flow. See Tune polling. |
| Webhook Enabled | Status Updates | true | Enables the inbound events endpoint, which is the primary status path. Requires the webhook service account and the Entitle webhook that you configure in Step 6 and Step 7. While false, the endpoint answers 404. |
| Approval Hook | Advanced | empty | Your subflow that replaces the built-in approval chain. See Customize the application. |
| Pre-Submit Validation Hook | Advanced | empty | Your subflow that replaces the built-in final validation. |
| Notification Hook | Advanced | empty | Your subflow that notifies requesters through another channel, such as email or chat. The built-in hook does nothing; the app writes the RITM comments either way. |
| Flow Override | Advanced | empty | Your subflow that replaces the entire fulfillment flow. |
| Log Level | Advanced | Error | Minimum severity the app writes to the system log: Debug, Info, Warn, or Error. Takes effect immediately. Raise it to Info or Debug only while troubleshooting. |
The built-in approval chain
When no Approval Hook is configured, the built-in approval chain runs in this order:
- Manager approval on the RITM, by the manager of the target user. The target user is the On Behalf Of user when that field is set, and otherwise the requester.
- If no manager resolves, the Default Approval Group approves instead. The two are mutually exclusive, so at most one of them runs.
- If the requested duration meets the CAB Escalation Duration threshold, or is Forever, and a CAB Approval Group is set, that group must give a second approval.
- If neither a manager nor a Default Approval Group is available, the chain rejects the request.
At most two approval levels apply to any request. Approval is fail-closed throughout: any error path denies rather than allows.
Customize the application
This section is for flow developers.
The application ships with a complete fulfillment flow, and its logic is read-only by design. You extend it through four override points, not by editing app artifacts. Each override point is a reference field on the Configuration record's Advanced tab:
| Field | What you provide | What it replaces |
|---|---|---|
| Pre-Submit Validation Hook | Subflow | The built-in final validation before submission to Entitle |
| Approval Hook | Subflow | The built-in approval chain: manager, then default group, then CAB |
| Notification Hook | Subflow | The built-in hook, which does nothing. The fulfillment flow writes requester comments either way. |
| Flow Override | Subflow | The entire Access Request fulfillment flow |
When a field is empty, the built-in behavior runs. When a field points at your subflow, a dispatcher invokes it at runtime through Flow Designer's Dynamic Flow flow logic, passing the documented inputs and reading the documented outputs back. The flow engine awaits the Approval and Pre-Submit hooks natively: the calling flow suspends without holding a thread or timing out, so your subflow can take hours or days. That includes waiting on human decisions, such as Ask For Approval, a chat prompt, or an email round-trip. The dispatcher starts the Notification Hook and Flow Override fire-and-forget, without waiting for them.
Requirements common to all overrides
- Build your override in your own scoped application or in global scope. You can't create records inside the Entitle application's scope.
- Match the shipped subflow's signature. The built-in Approval Hook, Pre-Submit Validation Hook, and Notification Hook subflows carry the exact input and output contract. For the Flow Override, the contract is the shipped Access Request Override Template. Input and output names, types, and reference tables must match exactly. A misspelled output is the same as no output.
- Extend rather than replace when you can. Your scope can call the built-in hook subflows. Your custom hook can call the shipped subflow as a step and add logic before, after, or around it. For example, it can run the built-in approval chain and then post the outcome to a chat channel. This is safe by design: the shipped hooks contain no dispatch logic, so recursion is impossible.
- All four overrides are subflows. The configuration pickers show only active subflows, so you can't select drafts or triggered flows.
- Set Accessible from: All application scopes on your subflow, and activate and publish it.
- All context arrives through the inputs. The application's tables are private, and your scope can't read them. Don't design a hook that queries them.
- The Approval and Pre-Submit Validation hooks run with the privileges of the requesting session. The Notification hook and Flow Override run as system. Writes from your scope to platform tables, such as
sc_req_itemwork notes, may generate Restricted Caller Access requests the first time. An admin approves them once.
Failure modes: know them before you build
Your subflow runs through a Dynamic Flow step, and two failure classes behave differently. The fulfillment flow's normal branches handle a hook that runs but returns a missing or unexpected output. A hook that can't start or throws stops the calling flow with an error. A hook can't start when it is inactive, isn't accessible from all scopes, or has the wrong signature. That error appears in the flow execution record under Workflow Studio > Operations, not as an application log line.
The following table shows how each override behaves in both failure classes:
| Override | Runs, but output missing or unexpected | Can't start, or throws |
|---|---|---|
| Pre-Submit Validation Hook | passed = false rejects. Always assign passed explicitly on every path, and don't rely on an unset value. | The fulfillment flow stops with an error and leaves the RITM open. |
| Approval Hook | Anything other than exactly approved, including no value, rejects the request. The RITM closes as Closed Incomplete with your failure_reason as the comment. If you didn't set one, the comment is Your Entitle access request was closed without access being granted. | The fulfillment flow stops with an error and leaves the RITM open. |
| Notification Hook | Has no outputs. | Started fire-and-forget: a failure shows in your subflow's own execution and doesn't affect the request. |
| Flow Override | Has no outputs. | The fulfillment flow stops with an error and leaves the RITM open. |
ImportantA broken Approval Hook never approves, and it doesn't fall back to the built-in chain. A hook that runs but returns anything other than
approvedrejects the request. A hook that can't start or throws halts fulfillment and leaves the RITM open for an administrator to close. Returnapproval_resulton every path, with a requester-appropriatefailure_reasonon denials, and test the hook as a normal requester before go-live.
Approval Hook
Replace the built-in approval chain. For example, delegate approval to an external IT service management (ITSM) or governance, risk, and compliance (GRC) system, use a different approval matrix, or apply auto-approval rules. Your hook bypasses the platform approval engine completely: ServiceNow creates no sysapproval_approver records unless your subflow creates them. You can use Ask For Approval inside your hook.
Inputs
The Approval Hook receives these inputs:
| Name | Type | Mandatory | Semantics |
|---|---|---|---|
requested_item | Reference → sc_req_item | ![]() | The RITM being fulfilled |
requesting_user | Record(s) → sys_user | ![]() | The user who needs the access |
on_behalf_of | Record(s) → sys_user | Set when a proxy requester submitted for someone else | |
duration_seconds | Integer | ![]() | Requested duration in seconds; -1 means Forever |
resource_display_name | String | ![]() | Human-readable resource name, for approval messages |
Outputs
The Approval Hook returns these outputs:
| Name | Type | Semantics |
|---|---|---|
approval_result | String | Return exactly approved, in lowercase, to allow. Any other value denies; use rejected by convention. The hook is fail-closed: an empty or missing value counts as rejected. |
failure_reason | String | Return with any denial. The app shows it verbatim to the requester in the RITM closure comment, so write it for end users. |
On a non-approved result, the app closes the RITM as Closed Incomplete with your failure_reason, and the Notification Hook fires with terminal_state = rejected.
Long-running approvals are supported: the flow engine waits for your subflow however long it takes. However, a hook that never completes leaves the request waiting indefinitely. If your organization needs a timeout, build your own, for example a Wait for a duration step that races the approval and then returns rejected.
Recipe: Minimal auto-approve for the Entitle-managed model. If Entitle governs approvals entirely and ServiceNow doesn't need to add a second approval layer, the whole hook is one step:
- Create a subflow with the Approval Hook's inputs and outputs. Copy the signature from the shipped Approval Hook subflow.
- Add a single Assign Subflow Outputs step:
approval_result=approved. - Publish the subflow with access from all scopes, and set it as the Approval Hook in the configuration.
Every request then passes straight to Entitle, where Entitle's own workflow performs the real approval.
Recipe: Extend rather than replace. Create your subflow with the same signature, and call the shipped Approval Hook subflow as its first step. The shipped subflow is public and embeddable. Map your inputs through, and then add your extra behavior, such as posting the outcome to Teams or Slack. Finally, assign the shipped hook's outputs to your own outputs.
Pre-Submit Validation Hook
This hook is the final check immediately before submission to Entitle. Use it to add organizational checks such as change freezes, risk scoring, or configuration management database (CMDB) lookups. What you give up is the built-in validation, which re-confirms eligibility and checks that the duration is in the allowed list. If your hook doesn't re-implement equivalent checks, they don't happen. Note the sequencing: approval runs before pre-submit validation.
Inputs: All of these inputs are mandatory: requested_item (Reference → sc_req_item), resource_sysid (String), resource_id (String), resource_type (String), duration_seconds (Integer, where -1 means Forever), and justification (String). The resource_id value is the Entitle resource's globally unique identifier (GUID).
Outputs
The Pre-Submit Validation Hook returns these outputs:
| Name | Type | Semantics |
|---|---|---|
passed | True/False | false rejects the request; true lets it proceed. Assign it on every path; an unset value is not a documented outcome. |
failure_reason | String | Shown verbatim to the requester in the RITM closure comment. |
When passed = false, the app closes the RITM as Closed Incomplete with Request rejected by pre-submit validation: <failure_reason>, the Notification Hook fires with terminal_state = validation_failed, and the app sends nothing to Entitle.
Recipe: Change-freeze gate. In your subflow, look up your freeze calendar. Inside a freeze window, assign passed = false and failure_reason = "Access requests are paused during the change freeze (until <date>)." Otherwise, assign passed = true. To keep the built-in eligibility and duration checks as well, call the shipped Pre-Submit Validation Hook subflow first, and combine its result with yours using AND.
Notification Hook
Notify requesters through another channel, such as Teams, Slack, or email, at each transition. The built-in hook does nothing. The fulfillment flow itself writes one RITM comment at submission and one at closure, independent of this hook. An override therefore adds a channel and never has to re-create or suppress those comments. The dispatcher starts the hook fire-and-forget: it has no outputs, the fulfillment flow doesn't wait for it, and a failure inside it shows only in your subflow's own execution record.
Inputs: requested_item (Reference → sc_req_item), terminal_state (String, using the values in the table below), entitle_request_id (String, once one exists), and failure_reason (String, populated for failure-type states).
The following table lists each terminal_state value:
terminal_state | Fired when | RITM comment the flow writes |
|---|---|---|
submitted | Successfully submitted to Entitle | Access request submitted to Entitle (ID: <id>). Awaiting confirmation. followed by Requested: <resource> for <duration> |
approved | Not fired in this release. Entitle's approved status counts as in-flight, and the app waits for granted. The value is retained so custom hooks built against it keep working. | None |
provisioned | Entitle reports access granted, or granted and since ended | Access provisioned successfully. or Access was provisioned and has since been revoked in Entitle. |
rejected | Approval denied, resource no longer eligible at fulfillment time, or Entitle rejected the request | Your approval failure_reason; You are no longer eligible for the requested resource.; or Access request rejected by Entitle. |
validation_failed | Pre-submit validation rejected the request | Request rejected by pre-submit validation: <failure_reason> |
failed | Submission or provisioning failed, or polling gave up after the Maximum Polling Age | The failure reason, or Access request failed in Entitle. when Entitle reports the failure without one |
expired | Entitle reports the request expired | Access request expired in Entitle. |
cancelled | The requester withdrew the request in Entitle before a decision | Access request was cancelled in Entitle. |
Two closures don't fire the hook: the flow stopping because no Configuration record exists, and the flow's catch-all error handler. Both still write a closure comment.
Recipe: Chat notifications. Create a subflow with the signature above. Branch on terminal_state, and call your Teams or Slack spoke with a message built from the inputs. The flow writes the RITM comments regardless, so you don't need to call anything to keep them.
Flow Override
Replace the entire fulfillment flow. Use this alternative when your organization's request lifecycle differs fundamentally. When the field is set, the shipped flow updates the RITM short description and description, starts your subflow fire-and-forget, and ends. None of the built-in behavior runs: no eligibility validation, no approval, no hooks, no Entitle submission, no tracking record, no notifications, and no RITM closure.
Contract: A single input, requested_item (Reference → sc_req_item), and no outputs.
Build your override by copying the shipped Access Request Override Template subflow, which declares the input and restates the obligations. At minimum, a conforming replacement must:
- Validate the request. The app does not re-check eligibility for you.
- Perform whatever approval your organization requires.
- Submit to Entitle. The Spoke's actions are the supported integration surface.
- Track status through to a terminal state.
- Close the RITM on every path, including failures. Otherwise, requests hang open.
Clone the catalog item
As an alternative to the Flow Override, you can duplicate the Request Entitle Access item and point the copy's Flow field at your own flow. The shipped flow and all hooks never run for your item. However, you also take ownership of the catalog experience, including the eligibility-driven resource picker, duration options, freshness checks, and the impersonation guard. Prefer the Flow Override when you want to keep the shipped item and user experience and replace only fulfillment. Clone the item only when the request form itself must change.
Configure and verify an override
- Go to BeyondTrust Entitle > Configuration, and open the Advanced tab.
- Set the relevant field to your subflow and save.
- Submit a test request and verify the divert:
- Flow executions: Under Workflow Studio > Operations, the relevant dispatcher subflow shows the override branch, and your subflow appears as its own child execution.
- RITM activity stream: Your hook's effects appear, and the corresponding default messages don't.
- Flow execution errors: A hook that couldn't start or threw shows as an error on the dispatcher's Dynamic Flow step. Check that your subflow is activated, accessible from all scopes, and matches the shipped signature.
To return to built-in behavior, clear the field. The app reads the configuration on each execution.
Use the following table to diagnose an override that isn't working:
| Symptom | Likely cause |
|---|---|
| The dispatcher's Dynamic Flow step errors and the RITM stays open | The subflow was deactivated after selection, isn't set to Accessible from: All application scopes, has a signature mismatch, or has an unhandled error inside it |
Every request is rejected, and the closure comment reads Your Entitle access request was closed without access being granted. | The approval subflow returns no approval_result, or a value other than exactly approved, and no failure_reason. Assign both outputs on every path. |
The RITM closed with Request rejected by pre-submit validation: and no reason | passed = false without a failure_reason |
| Your hook's record updates don't apply | A Restricted Caller Access request is waiting for admin approval |
| Requests hang open with Flow Override set | Your subflow must close the RITM on every path |
Operations and maintenance
Status reconciliation: how requests get closed
Two mechanisms can drive a submitted request to closure. They share the same terminal-state machinery and are safe to run together:
- Webhook: default, push-based. Entitle streams audit events to the app's inbound endpoint, and the app filters for whole-request status changes and applies them immediately. This is the primary path: Webhook Enabled ships as
true. Once you configure the service account and the Entitle webhook in Step 6 and Step 7, granted, rejected, and cancelled outcomes close the RITM within seconds. - Polling: optional, opt-in. The Status Reconciliation scheduled flow ships inactive; see Enable status polling. When activated, it runs every minute and polls each in-flight request against Entitle. However, it polls each individual request at most once per Polling Interval, which defaults to 5 minutes. Because it is a high-frequency job, tune the rate only by editing the configuration field, and never modify the flow trigger. Use polling as a fallback alongside the webhook, or as the only path where your organization doesn't permit inbound webhooks.
Track in-flight and historical requests under BeyondTrust Entitle > Requests. The states are external, meaning submitted and awaiting Entitle, and the terminal states provisioned, rejected, failed, expired, and cancelled. When a request reaches a terminal state, the app closes the RITM, and the reason becomes the requester's closure comment.
The parent Request closes through the platform's standard roll-up when its last requested item closes. It closes as Closed Complete, or as Closed Incomplete if the item did not complete. A Request that also holds other items, for example several ordered through one cart, stays open until those finish too. To drive that roll-up, the app sets the RITM's Stage field to complete or closed_incomplete at closure, and doesn't touch Stage anywhere else. Any intermediate stages remain part of your process. Because the app defines no stage labels, the Stage field shows these raw values.
Webhook behavior and monitoring
Endpoint: POST https://<instance>.service-now.com/api/x_bets_entitle/entitle_events_api/v1/events
Authentication is standard ServiceNow Basic authentication, enforced by the platform. The endpoint's access control list (ACL) requires the x_bets_entitle.api role, and the handler itself contains no credential logic. For initial configuration, see Step 6 and Step 7.
- The platform rejects failed authentication before the app runs, so bad credentials produce no application log line. Diagnose them from the platform's authentication logs.
- Entitle automatically disables a webhook after repeated delivery failures: approximately a dozen non-2xx responses within a couple of hours. The endpoint deliberately answers 200 to everything it can, including malformed payloads, irrelevant events, unknown request IDs, and even its own handler errors. As a result, only real authentication failures or the 404 feature gate count toward that limit. If deliveries stop, check Entitle's webhook status first.
- You can disable the webhook at any time by setting the configuration field to
false, but only if you have activated polling. With neither path active, in-flight requests stayexternaland RITMs stay open.
Tune polling
- Polling applies only if you have activated the Status Reconciliation flow. With the webhook alone, nothing polls.
- Polling Interval is a per-request minimum, so if you lower it, API traffic increases roughly in proportion to your number of concurrent in-flight requests. The default of 5 minutes suits most volumes. If you run polling alongside the webhook and want to minimize API calls, raise it.
- The app logs poll failures and fails open: it retries the record on the next due cycle, up to the Maximum Polling Age.
- Maximum Polling Age, which defaults to 7 days, limits how long the app polls any one request. If a request has no final Entitle status by then, the app closes it as
failed, closes its RITM as Closed Incomplete with an explanatory comment to the requester, and logs an error. This typically happens because of an Entitle status the app doesn't recognize, or an Entitle API error that never clears. The app does not notify Entitle, so if Entitle later approves the request, the user gets access while the RITM stays closed. If your Entitle approvals legitimately take longer than a week, raise the value.
Credential rotation
Both credentials are record-level edits, with no code or flow changes:
- Entitle API token: Update it in Entitle first, and then in ServiceNow. Before the current token expires, create a replacement API token in Entitle under Org settings > Tokens. Then open the API Key credential from Step 3 under All > Connections & Credentials > Credentials, replace the API Key, and save. Once the new token is working, Revoke the old token in Entitle.
- Webhook service account password: Update it in ServiceNow first, and then in Entitle. Change the service account's password, and then update the Entitle webhook header with the new Base64 value, using the same procedure as Step 7.
Scheduled jobs
The app uses two scheduled jobs:
| Job | Schedule | Purpose |
|---|---|---|
| Status Reconciliation scheduled flow | Every 1 minute when activated; ships inactive | Optional job that polls in-flight requests. Polling Interval governs the per-request cadence, and the app stops polling a request after Maximum Polling Age. Because the job is high-frequency, tune it only through these fields, never by editing the trigger. |
| Purge Expired Entitle Eligibility | Daily at 10:00 | Deletes expired eligibility cache rows. |
Logs and diagnostics
The app writes level-gated messages to the system log, syslog.list, with source prefixes of the form [Entitle:<Component>]. The hook dispatch path also writes [Entitle] and [Entitle Flow] warnings. Set Log Level on the Configuration record. It ships as Error, which is right for normal operation. Raise it to Info or Debug while troubleshooting, and set it back afterward. Changes take effect immediately. Application-scoped entries also appear under System Logs > Application Logs, filtered to BeyondTrust Entitle.
Upgrades
If you edited any shipped record directly, for example by renaming the catalog item, the platform marks those records as customized and skips them during app upgrades. After each upgrade, review the skipped records in the upgrade history, and deliberately re-apply or revert your changes. Overrides you configure through the hook fields are unaffected by upgrades, because they live in your scope.
When you activate the Status Reconciliation flow, that counts as a customization of that one record. After each upgrade, check that the flow is still active if you rely on polling, and review it in the skipped-records list. Its content rarely changes, so accepting your version is normally the right choice.
Troubleshooting
Resource list on the request form is empty
Symptoms: The Resource field offers no options, or the form shows an eligibility error.
Possible causes and solutions:
- The user has no JIT-eligible resources in Entitle. Verify their eligibility in the Entitle admin console.
- The Entitle API call failed. Check
syslogfor[Entitle:*]errors, and verify the alias URL and token. See the error code reference below. - Offered Resource Types hides every type the user is eligible for. For example, the user is eligible only for roles, and the setting is Bundles only. The cache is fine, so a refresh doesn't help. Change the setting, or grant the user a resource of an offered type in Entitle.
The request form loads slowly for a user
Symptoms: A noticeable delay before the Resource list populates.
Possible causes and solutions: A first load or a hard-expired cache triggers a synchronous eligibility fetch from Entitle. Later loads come from the cache. No action is needed unless it happens on every load. If it does, check the Eligibility Soft TTL and Eligibility Hard Expiry settings on the Configuration record.
Every request is rejected immediately
Symptoms: RITMs close as Closed Incomplete moments after submission, before any approval.
Possible causes and solutions:
- No manager resolves for the target user, and no Default Approval Group is set. The built-in chain is fail-closed. Set a Default Approval Group.
- A configured Approval Hook is broken. See Configure and verify an override.
RITM stays open long after Entitle shows a decision
Symptoms: The Entitle console shows granted or rejected, but the ServiceNow request record remains external, and the RITM stays open.
Possible causes and solutions:
- The webhook isn't delivering. In Entitle, verify the webhook, which Entitle may have disabled automatically after delivery failures. Also verify the service account credentials, and confirm that Webhook Enabled is
true. See Webhook deliveries are failing. - You rely on polling, but the Status Reconciliation flow isn't active; it ships inactive. The Maximum Polling Age applies only while polling is active. On a webhook-only installation, a request whose final webhook event never arrives stays open until you close it.
- The polling interval is set very high. Check Polling Interval on the Configuration record.
- Poll or handler errors occurred. Temporarily set Log Level to
Info, and check the application log for[Entitle:*]entries. The app writes an unrecognized Entitle status to the request record's Error Message field and keeps polling until the Maximum Polling Age closes the request. See RITM closed Closed Incomplete: no final status.
Webhook deliveries are failing
Symptoms: Entitle reports delivery failures, or has automatically disabled the webhook.
Possible causes and solutions:
- 401 or 403: The service account credentials are wrong or expired, or the account lacks
x_bets_entitle.api. Diagnose from the platform authentication logs, because the app logs nothing for authentication failures. - 404: Webhook Enabled is
falseon the Configuration record.
RITM closed _Closed Incomplete_ with a validation message
Symptoms: The closure comment reads Request rejected by pre-submit validation: ….
Possible causes and solutions: Pre-submit validation, either built-in or from a custom hook, rejected the request. The comment carries the reason. If a custom hook is configured, your organization authors its failure_reason.
RITM closed Closed Incomplete: no final status from Entitle
Symptoms: The closure comment reads No final status was received from Entitle within N days of submission, so this request is no longer being tracked. …, and the request record's State is failed.
Possible causes and solutions: Polling gave up after the Maximum Polling Age. The system log, syslog.list, has an error-level entry that begins with Gave up polling Entitle request. Its Last recorded error: value shows what the app last saw: usually an Entitle status it doesn't recognize, or an Entitle API error that never cleared.
- Check the request in Entitle. It may still be pending there. If Entitle later approves it, the requester receives access even though the RITM stays closed.
- If your Entitle approvals routinely take longer than the limit, raise Maximum Polling Age (days) on the Configuration record.
- If the log shows an unrecognized Entitle status, report it to BeyondTrust support so that BeyondTrust can map it.
Entitle API error codes
The Spoke returns these codes, and the app logs them. Use them as stable values to branch or search on:
| Code | Meaning |
|---|---|
auth_error | 401 or 403. The API token is invalid or was rotated. |
not_found | 404 |
conflict | 409 |
validation_error | 422, or missing local configuration |
rate_limited | 429 |
upstream_error | 5xx from Entitle |
client_error | Other 4xx |
connection_error | Network or firewall problem on the path to the Entitle API host |
Security considerations
-
Credentials: The Entitle API token is an organization-level administrator credential. The API Key credential attached to the Spoke's connection alias stores it encrypted. Give the token an expiration in Entitle, and rotate it on your normal schedule. The webhook uses a dedicated service account with a single-purpose role,
x_bets_entitle.api, that grants no table access. The endpoint is POST-only, requires authentication, and answers 404 while Webhook Enabled isfalse. -
Access control: The app's tables are private to its scope; end users interact only through the catalog item. Administration requires
x_bets_entitle.admin. User criteria restrict the catalog item tox_bets_entitle.requester. -
Application integrity: App logic is read-only on installing instances. Customers and support can read the code, but extend it only through the hook contracts, never by editing app internals.
-
Impersonation guard: You can't submit access requests while impersonating another user. The app enforces this on both the client side and the server side.
-
Data stored in ServiceNow: The app maintains four private tables:
- The singleton configuration
- A per-user eligibility cache of resource names and IDs that a user may request, refreshed from Entitle and purged after expiry
- An internal catalog of Entitle resources, meaning roles and bundles
- One request tracking row per submitted access request, holding the Entitle request ID, state, timestamps, and error messages
The app writes requester-visible status as comments on the RITM.
-
To view the App Privacy Policy page, go to BeyondTrust Entitle > App Privacy Policy. It describes data collection, use, sharing, and retention. The Help page summarizes configuration, roles, and troubleshooting inside the instance.
Best practices
- Set a Default Approval Group before go-live. It is the fallback for every user without a manager, and the built-in chain rejects requests when neither is available.
- Keep Duration Options aligned with Entitle whenever either side changes. There is no automatic sync. In Entitle, the settings are under Administration > Org Settings > JIT Requests.
- Connect the webhook before go-live. It is the default status path, and nothing closes a request without it. If you want a fallback for missed deliveries, or can't accept inbound webhooks, also activate the optional Status Reconciliation polling flow.
- Extend hooks rather than replace them where possible. When your custom hook calls the shipped subflow, the built-in behavior and your additions stay in one place.
- Test overrides as a normal requester, not as an admin. Privilege differences can mask access problems in custom hooks.
- Review upgrade-skipped records after each app upgrade if you have edited any shipped record, such as a renamed catalog item.
- Rotate the Entitle API token and webhook service-account password on your organization's normal credential schedule. For steps, see Credential rotation.
Additional resources
- BeyondTrust Entitle API reference
- Entitle: Org settings: View and manage tokens
- BeyondTrust Pathfinder: Org settings
- ServiceNow: Subflows in Flow Designer
- ServiceNow: Dynamic flows flow logic
Updated 12 minutes ago
